diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorPlugin.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorPlugin.java index 404f01cf..410e83e9 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorPlugin.java @@ -30,13 +30,10 @@ import net.consensys.linea.AbstractLineaRequiredPlugin; import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import net.consensys.linea.jsonrpc.JsonRpcManager; -import net.consensys.linea.sequencer.txpoolvalidation.metrics.TransactionPoolProfitabilityMetrics; -import net.consensys.linea.sequencer.txpoolvalidation.metrics.ValidatorProfitabilityMetrics; import org.hyperledger.besu.datatypes.Address; 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.TransactionPoolValidatorService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; @@ -49,7 +46,6 @@ @Slf4j @AutoService(BesuPlugin.class) public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPlugin { - private BesuContext besuContext; private BesuConfiguration besuConfiguration; private TransactionPoolValidatorService transactionPoolValidatorService; private TransactionSimulationService transactionSimulationService; @@ -57,7 +53,6 @@ public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPl @Override public void doRegister(final BesuContext context) { - besuContext = context; besuConfiguration = context .getService(BesuConfiguration.class) @@ -87,14 +82,6 @@ public void doRegister(final BesuContext context) { public void start() { super.start(); - final var validatorProfitabilityMetrics = - new ValidatorProfitabilityMetrics( - besuConfiguration, metricsSystem, profitabilityConfiguration()); - - final var transactionPoolProfitabilityMetrics = - new TransactionPoolProfitabilityMetrics( - besuConfiguration, metricsSystem, profitabilityConfiguration()); - try (Stream lines = Files.lines( Path.of(new File(transactionPoolValidatorConfiguration().denyListPath()).toURI()))) { @@ -126,37 +113,6 @@ public void start() { l1L2BridgeSharedConfiguration(), rejectedTxJsonRpcManager)); - final var besuEventsService = - besuContext - .getService(BesuEvents.class) - .orElseThrow( - () -> new RuntimeException("Failed to obtain BesuEvents from the BesuContext.")); - - besuEventsService.addBlockAddedListener( - addedBlockContext -> { - try { - validatorProfitabilityMetrics.handleBlockAdded(addedBlockContext); - } catch (final Exception e) { - log.warn( - "Error calculating transaction profitability for block {}({})", - addedBlockContext.getBlockHeader().getNumber(), - addedBlockContext.getBlockHeader().getBlockHash(), - e); - } - }); - - besuEventsService.addTransactionAddedListener( - transaction -> { - try { - transactionPoolProfitabilityMetrics.handleTransactionAdded(transaction); - } catch (Exception e) { - log.warn( - "Error recording transaction profitability metrics for {}: {}", - transaction.getHash(), - e.getMessage()); - } - }); - } catch (Exception e) { throw new RuntimeException(e); } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/TransactionPoolProfitabilityMetrics.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/TransactionPoolProfitabilityMetrics.java deleted file mode 100644 index 4b89c734..00000000 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/TransactionPoolProfitabilityMetrics.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright Consensys Software Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package net.consensys.linea.sequencer.txpoolvalidation.metrics; - -import java.util.concurrent.atomic.AtomicReference; - -import lombok.extern.slf4j.Slf4j; -import net.consensys.linea.bl.TransactionProfitabilityCalculator; -import net.consensys.linea.config.LineaProfitabilityConfiguration; -import net.consensys.linea.metrics.LineaMetricCategory; -import org.hyperledger.besu.datatypes.Transaction; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.plugin.services.metrics.Counter; -import org.hyperledger.besu.plugin.services.metrics.Histogram; -import org.hyperledger.besu.plugin.services.metrics.LabelledGauge; -import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; - -/** - * Tracks profitability metrics for transactions in the transaction pool. Specifically monitors the - * ratio of profitable priority fee to actual priority fee: - * profitablePriorityFeePerGas/transaction.priorityFeePerGas - * - *

Provides: - Lowest ratio seen (minimum profitability) - Highest ratio seen (maximum - * profitability) - Distribution histogram of ratios - */ -@Slf4j -public class TransactionPoolProfitabilityMetrics { - private static final double[] HISTOGRAM_BUCKETS = {0.1, 0.5, 0.8, 1.0, 1.2, 1.5, 2.0, 5.0, 10.0}; - - private final TransactionProfitabilityCalculator profitabilityCalculator; - private final LineaProfitabilityConfiguration profitabilityConf; - private final BesuConfiguration besuConfiguration; - - private final LabelledMetric profitabilityHistogram; - private final Counter invalidTransactionCount; - - // Thread-safe references for gauge values - private final AtomicReference currentLowest = new AtomicReference<>(Double.MAX_VALUE); - private final AtomicReference currentHighest = new AtomicReference<>(0.0); - - public TransactionPoolProfitabilityMetrics( - final BesuConfiguration besuConfiguration, - final MetricsSystem metricsSystem, - final LineaProfitabilityConfiguration profitabilityConf) { - - this.besuConfiguration = besuConfiguration; - this.profitabilityConf = profitabilityConf; - this.profitabilityCalculator = new TransactionProfitabilityCalculator(profitabilityConf); - - // Min/Max gauges with DoubleSupplier - LabelledGauge lowestProfitabilityRatio = - metricsSystem.createLabelledGauge( - LineaMetricCategory.PROFITABILITY, - "txpool_profitability_ratio_min", - "Lowest profitability ratio seen"); - lowestProfitabilityRatio.labels(currentLowest::get); - - LabelledGauge highestProfitabilityRatio = - metricsSystem.createLabelledGauge( - LineaMetricCategory.PROFITABILITY, - "txpool_profitability_ratio_max", - "Highest profitability ratio seen"); - highestProfitabilityRatio.labels(currentHighest::get); - - // Running statistics - this.profitabilityHistogram = - metricsSystem.createLabelledHistogram( - LineaMetricCategory.PROFITABILITY, - "txpool_profitability_ratio_summary", - "Summary statistics of profitability ratios", - HISTOGRAM_BUCKETS, - "type"); - - this.invalidTransactionCount = - metricsSystem.createCounter( - LineaMetricCategory.PROFITABILITY, - "txpool_invalid_transaction_count", - "Number of transactions that couldn't be processed for profitability"); - - // Pre-create histogram buckets - for (double bucket : HISTOGRAM_BUCKETS) { - profitabilityHistogram.labels(String.format("le_%.1f", bucket)); - } - } - - public void handleTransactionAdded(Transaction transaction) { - try { - if (transaction.getMaxPriorityFeePerGas().isEmpty()) { - invalidTransactionCount.inc(); - log.trace("Skipping transaction {} - no priority fee", transaction.getHash()); - return; - } - - Wei profitablePriorityFeePerGas = - profitabilityCalculator.profitablePriorityFeePerGas( - transaction, - profitabilityConf.txPoolMinMargin(), - transaction.getGasLimit(), - besuConfiguration.getMinGasPrice()); - - Wei actualPriorityFeePerGas = Wei.fromQuantity(transaction.getMaxPriorityFeePerGas().get()); - - if (actualPriorityFeePerGas.toLong() > 0) { - double ratio = - profitablePriorityFeePerGas.toBigInteger().doubleValue() - / actualPriorityFeePerGas.toBigInteger().doubleValue(); - - updateRunningStats(ratio); - - log.trace("Recorded profitability ratio {} for tx {}", ratio, transaction.getHash()); - } else { - invalidTransactionCount.inc(); - log.trace("Skipping transaction {} - zero priority fee", transaction.getHash()); - } - } catch (Exception e) { - invalidTransactionCount.inc(); - log.warn( - "Failed to record profitability metrics for tx {}: {}", - transaction.getHash(), - e.getMessage()); - } - } - - private void updateRunningStats(double ratio) { - // Update lowest seen - currentLowest.updateAndGet(current -> Math.min(current, ratio)); - - // Update highest seen - currentHighest.updateAndGet(current -> Math.max(current, ratio)); - - // Record the observation in summary - profitabilityHistogram.labels("profitability").observe(ratio); - } -} diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/ValidatorProfitabilityMetrics.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/ValidatorProfitabilityMetrics.java deleted file mode 100644 index 4c018811..00000000 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/metrics/ValidatorProfitabilityMetrics.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Consensys Software Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package net.consensys.linea.sequencer.txpoolvalidation.metrics; - -import java.math.BigInteger; - -import net.consensys.linea.bl.TransactionProfitabilityCalculator; -import net.consensys.linea.config.LineaProfitabilityConfiguration; -import net.consensys.linea.metrics.LineaMetricCategory; -import org.hyperledger.besu.datatypes.Quantity; -import org.hyperledger.besu.datatypes.Transaction; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.plugin.data.AddedBlockContext; -import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.plugin.services.metrics.Counter; - -public class ValidatorProfitabilityMetrics { - - private final Counter lowProfitabilityCounter; - private final Counter highProfitabilityCounter; - private final Counter avgProfitabilityCounter; - private final TransactionProfitabilityCalculator profitabilityCalculator; - private final LineaProfitabilityConfiguration profitabilityConf; - private final BesuConfiguration besuConfiguration; - - public ValidatorProfitabilityMetrics( - final BesuConfiguration besuConfiguration, - final MetricsSystem metricsSystem, - final LineaProfitabilityConfiguration profitabilityConf) { - - this.besuConfiguration = besuConfiguration; - - this.lowProfitabilityCounter = - metricsSystem.createCounter( - LineaMetricCategory.PROFITABILITY, - "tx_pool_profitability_low", - "Number of low profitability transactions"); - - this.avgProfitabilityCounter = - metricsSystem.createCounter( - LineaMetricCategory.PROFITABILITY, - "tx_pool_profitability_avg", - "Number of average profitability transactions"); - - this.highProfitabilityCounter = - metricsSystem.createCounter( - LineaMetricCategory.PROFITABILITY, - "tx_pool_profitability_high", - "Number of high profitability transactions"); - - this.profitabilityConf = profitabilityConf; - - this.profitabilityCalculator = new TransactionProfitabilityCalculator(profitabilityConf); - } - - public void recordProfitabilityLevel(double profitabilityRatio) { - if (profitabilityRatio < 1.0) { - lowProfitabilityCounter.inc(); - } else if (profitabilityRatio >= 1.0 && profitabilityRatio <= 2.0) { - avgProfitabilityCounter.inc(); - } else { - highProfitabilityCounter.inc(); - } - } - - public void handleBlockAdded(AddedBlockContext blockContext) { - blockContext.getBlockBody().getTransactions().forEach(this::calculateTransactionProfitability); - } - - private void calculateTransactionProfitability(Transaction transaction) { - Wei profitablePriorityFeePerGas = - profitabilityCalculator.profitablePriorityFeePerGas( - transaction, - profitabilityConf.txPoolMinMargin(), - transaction.getGasLimit(), - besuConfiguration.getMinGasPrice()); - - Quantity priorityFeePerGas = - transaction.getMaxPriorityFeePerGas().map(Quantity.class::cast).orElse(Wei.ZERO); - - if (!priorityFeePerGas.getAsBigInteger().equals(BigInteger.ZERO)) { - double profitabilityRatio = - profitablePriorityFeePerGas.getAsBigInteger().doubleValue() - / priorityFeePerGas.getAsBigInteger().doubleValue(); - recordProfitabilityLevel(profitabilityRatio); - } - } -}