Skip to content

Commit

Permalink
Refctor to respect the requirement
Browse files Browse the repository at this point in the history
Signed-off-by: Fabio Di Fabio <[email protected]>
  • Loading branch information
fab-10 committed Oct 25, 2024
1 parent 1261400 commit 2bcf53b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 150 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
releaseVersion=0.8.0-rc4.1
besuVersion=24.10-develop-829db23
besuVersion=24.10-local
arithmetizationVersion=0.8.0-rc4
besuArtifactGroup=io.consensys.linea-besu
distributionIdentifier=linea-sequencer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,35 +113,16 @@ public boolean isProfitable(

final Wei profitablePriorityFee =
profitablePriorityFeePerGas(transaction, minMargin, gas, minGasPriceWei);
final Wei profitableGasPrice = baseFee.add(profitablePriorityFee);

if (payingGasPrice.lessThan(profitableGasPrice)) {
log(
log.atDebug(),
context,
transaction,
minMargin,
payingGasPrice,
baseFee,
profitablePriorityFee,
profitableGasPrice,
gas,
minGasPriceWei);
return false;
}

log(
log.atTrace(),
return isProfitable(
context,
profitablePriorityFee,
transaction,
minMargin,
payingGasPrice,
baseFee,
profitablePriorityFee,
profitableGasPrice,
payingGasPrice,
gas,
minGasPriceWei);
return true;
}

public boolean isProfitable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import net.consensys.linea.AbstractLineaRequiredPlugin;
import net.consensys.linea.config.LineaProfitabilityConfiguration;
import net.consensys.linea.metrics.LineaMetricCategory;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.data.AddedBlockContext;
Expand Down Expand Up @@ -107,7 +108,7 @@ public synchronized void onInitialSyncRestart() {
private void initMetrics(final LineaProfitabilityConfiguration lineaProfitabilityConfiguration) {
final var confLabelledGauge =
metricsSystem.createLabelledGauge(
LineaMetricCategory.PROFITABILITY,
BesuMetricCategory.ETHEREUM,
"conf",
"Profitability configuration values at runtime",
"field");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.BesuPlugin;
import org.hyperledger.besu.plugin.services.BesuConfiguration;
import org.hyperledger.besu.plugin.services.BesuEvents;
import org.hyperledger.besu.plugin.services.TransactionSelectionService;

/**
Expand Down Expand Up @@ -89,7 +88,7 @@ public void start() {
lineaRejectedTxReportingConfiguration)
.start());

final var selectorProfitabilityMetrics = new SelectorProfitabilityMetrics();
final var selectorProfitabilityMetrics = new SelectorProfitabilityMetrics(metricsSystem);

transactionSelectionService.registerPluginTransactionSelectorFactory(
new LineaTransactionSelectorFactory(
Expand All @@ -101,28 +100,6 @@ public void start() {
createLimitModules(tracerConfiguration()),
rejectedTxJsonRpcManager,
selectorProfitabilityMetrics));

final var besuEventsService =
besuContext
.getService(BesuEvents.class)
.orElseThrow(
() -> new RuntimeException("Failed to obtain BesuEvents from the BesuContext."));

// Add a block added listener to handle profitability calculations when a new block is added
besuEventsService.addBlockAddedListener(
addedBlockContext -> {
try {
selectorProfitabilityMetrics.handleNewBlock(
addedBlockContext.getBlockHeader(),
addedBlockContext.getBlockBody().getTransactions());
} catch (final Exception e) {
log.warn(
"Error calculating transaction profitability for block {}({})",
addedBlockContext.getBlockHeader().getNumber(),
addedBlockContext.getBlockHeader().getBlockHash(),
e);
}
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,115 +15,58 @@

package net.consensys.linea.sequencer.txselection.metrics;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import lombok.extern.slf4j.Slf4j;
import org.hyperledger.besu.datatypes.Hash;
import net.consensys.linea.metrics.LineaMetricCategory;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.LabelledMetric;
import org.hyperledger.besu.plugin.services.metrics.Summary;

@Slf4j
public class SelectorProfitabilityMetrics {
private final LabelledMetric<Summary> summaries;

private final Map<Long, Map<Hash, TransactionProfitabilityData>> txProfitabilityDataCacheByBlock =
new ConcurrentHashMap<>();

/**
* Handles the list of transactions by calculating their profitability based on the supplied cache
* of profitable priority fees.
*
* @param blockHeader the block header
* @param transactions The list of transactions to process
*/
public void handleNewBlock(
final BlockHeader blockHeader, List<? extends Transaction> transactions) {

log.info(
"New block number {}, txProfitabilityDataCache content: {}",
blockHeader.getNumber(),
txProfitabilityDataCacheByBlock);

purgePreviousBlockFromCache(blockHeader.getNumber());

// get and remove cached data for this block
final var txProfitabilityDataCache =
txProfitabilityDataCacheByBlock.remove(blockHeader.getNumber());

// if the cache is empty we are not building blocks, so nothing to do
if (txProfitabilityDataCache != null && !txProfitabilityDataCache.isEmpty()) {
final Wei baseFee =
blockHeader
.getBaseFee()
.map(Wei::fromQuantity)
.orElseThrow(() -> new IllegalStateException("Base fee market expected"));
transactions.forEach(tx -> process(txProfitabilityDataCache, baseFee, tx));
}
public SelectorProfitabilityMetrics(final MetricsSystem metricsSystem) {
this.summaries =
metricsSystem.createLabelledSummary(
BesuMetricCategory.ETHEREUM,
"selection_priority_fee_ratio",
"The ratio between the effective priority fee and the calculated one",
"phase");
}

private void purgePreviousBlockFromCache(final long newBlockNumber) {
// remove all cached data of previous blocks
for (final var cachedBlockNumber : txProfitabilityDataCacheByBlock.keySet()) {
if (cachedBlockNumber < newBlockNumber) {
txProfitabilityDataCacheByBlock.remove(cachedBlockNumber);
}
}
public enum Phase {
PRE_PROCESSING,
POST_PROCESSING
}

/**
* Processes an individual transaction to determine its profitability level.
*
* @param txProfitabilityDataCache
* @param baseFee
* @param transaction The transaction being processed
*/
private void process(
final Map<Hash, TransactionProfitabilityData> txProfitabilityDataCache,
public void track(
final Phase phase,
final long blockNumber,
final Transaction tx,
final Wei baseFee,
Transaction transaction) {
final var selectorProfitabilityData = txProfitabilityDataCache.remove(transaction.getHash());
if (selectorProfitabilityData != null) {
final var effectivePriorityFee =
selectorProfitabilityData.effectiveGasPrice.subtract(baseFee);
final var ratio =
selectorProfitabilityData.profitablePriorityFee.getValue().doubleValue()
/ effectivePriorityFee.getValue().doubleValue();
log.info(
"Tx {} profitability data found {}, baseFee {}, effectivePayingPriorityFee {}, ratio (calculatedProfitablePriorityFee/effectivePayingPriorityFee) {}",
transaction.getHash(),
selectorProfitabilityData,
baseFee.toHumanReadableString(),
effectivePriorityFee.toHumanReadableString(),
ratio);
} else {
log.info("Cached profitability data not found for tx {}", transaction.getHash());
}
}
final Wei effectiveGasPrice,
final Wei profitablePriorityFee) {
final var effectivePriorityFee = effectiveGasPrice.subtract(baseFee);
final var ratio =
effectivePriorityFee.getValue().doubleValue()
/ profitablePriorityFee.getValue().doubleValue();

public void remember(
final long blockNumber,
final Hash hash,
final Wei transactionGasPrice,
final Wei profitablePriorityFeePerGas) {
txProfitabilityDataCacheByBlock
.computeIfAbsent(blockNumber, unused -> new HashMap<>())
.put(
hash,
new TransactionProfitabilityData(transactionGasPrice, profitablePriorityFeePerGas));
}
summaries.labels(phase.name()).observe(ratio);

record TransactionProfitabilityData(Wei effectiveGasPrice, Wei profitablePriorityFee) {
@Override
public String toString() {
return "{"
+ "effectivePaidGasPrice="
+ effectiveGasPrice.toHumanReadableString()
+ ", calculatedProfitablePriorityFee="
+ profitablePriorityFee.toHumanReadableString()
+ '}';
}
log.atTrace()
.setMessage(
"{}: block[{}] tx {} , baseFee {}, effectiveGasPrice {}, ratio (effectivePayingPriorityFee {} / calculatedProfitablePriorityFee {}) {}")
.addArgument(phase)
.addArgument(blockNumber)
.addArgument(tx.getHash())
.addArgument(baseFee::toHumanReadableString)
.addArgument(effectiveGasPrice::toHumanReadableString)
.addArgument(effectivePriorityFee::toHumanReadableString)
.addArgument(profitablePriorityFee::toHumanReadableString)
.addArgument(ratio)
.log();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_UNPROFITABLE;
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_UNPROFITABLE_RETRY_LIMIT;
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_UNPROFITABLE_UPFRONT;
import static net.consensys.linea.sequencer.txselection.metrics.SelectorProfitabilityMetrics.Phase.POST_PROCESSING;
import static net.consensys.linea.sequencer.txselection.metrics.SelectorProfitabilityMetrics.Phase.PRE_PROCESSING;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;

import java.util.LinkedHashSet;
Expand Down Expand Up @@ -98,9 +100,22 @@ public TransactionSelectionResult evaluateTransactionPreProcessing(
final Transaction transaction = evaluationContext.getPendingTransaction().getTransaction();
final long gasLimit = transaction.getGasLimit();

final var profitablePriorityFeePerGas =
transactionProfitabilityCalculator.profitablePriorityFeePerGas(
transaction, profitabilityConf.minMargin(), gasLimit, minGasPrice);

selectorProfitabilityMetrics.track(
PRE_PROCESSING,
evaluationContext.getPendingBlockHeader().getNumber(),
transaction,
baseFee,
evaluationContext.getTransactionGasPrice(),
profitablePriorityFeePerGas);

// check the upfront profitability using the gas limit of the tx
if (!transactionProfitabilityCalculator.isProfitable(
"PreProcessing",
profitablePriorityFeePerGas,
transaction,
profitabilityConf.minMargin(),
baseFee,
Expand Down Expand Up @@ -156,6 +171,14 @@ public TransactionSelectionResult evaluateTransactionPostProcessing(
gasUsed,
evaluationContext.getMinGasPrice());

selectorProfitabilityMetrics.track(
POST_PROCESSING,
evaluationContext.getPendingBlockHeader().getNumber(),
transaction,
baseFee,
evaluationContext.getTransactionGasPrice(),
profitablePriorityFeePerGas);

if (!transactionProfitabilityCalculator.isProfitable(
"PostProcessing",
profitablePriorityFeePerGas,
Expand All @@ -168,12 +191,6 @@ public TransactionSelectionResult evaluateTransactionPostProcessing(
rememberUnprofitable(transaction);
return TX_UNPROFITABLE;
}

selectorProfitabilityMetrics.remember(
evaluationContext.getPendingBlockHeader().getNumber(),
transaction.getHash(),
evaluationContext.getTransactionGasPrice(),
profitablePriorityFeePerGas);
}
return SELECTED;
}
Expand Down

0 comments on commit 2bcf53b

Please sign in to comment.