diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/LineaPluginTestBase.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/LineaPluginTestBase.java index 6ad55f564..e44d7ec1b 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/LineaPluginTestBase.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/LineaPluginTestBase.java @@ -147,7 +147,8 @@ private BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis( "LineaEstimateGasEndpointPlugin", "LineaSetExtraDataEndpointPlugin", "LineaTransactionPoolValidatorPlugin", - "LineaTransactionSelectorPlugin")); + "LineaTransactionSelectorPlugin", + "LineaSendBundleEndpointPlugin")); return besu.create(nodeConfBuilder.build()); } diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasCompatibilityModeTest.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasCompatibilityModeTest.java index da41344f5..9fcf28fe3 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasCompatibilityModeTest.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasCompatibilityModeTest.java @@ -71,7 +71,7 @@ public void lineaEstimateGasPriorityFeeMinGasPriceLowerBound() { final Account sender = accounts.getSecondaryBenefactor(); final CallParams callParams = - new CallParams(null, sender.getAddress(), null, "", "", "0", null, null, null); + new CallParams(null, sender.getAddress(), null, null, "", "", "0", null, null, null); final var reqLinea = new LineaEstimateGasRequest(callParams); final var respLinea = reqLinea.execute(minerNode.nodeRequests()).getResult(); diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasModuleLimitOverflowTest.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasModuleLimitOverflowTest.java index cff3e6e72..7d76243db 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasModuleLimitOverflowTest.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasModuleLimitOverflowTest.java @@ -50,6 +50,7 @@ public void estimateGasFailsForExceedingModuleLineCountTest() throws Exception { new EstimateGasTest.CallParams( null, sender.getAddress(), + null, simpleStorage.getContractAddress(), null, payload.toHexString(), diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java index 30d3ad952..f9aa62a2a 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java @@ -99,6 +99,7 @@ public void lineaEstimateGasMatchesEthEstimateGas() { new CallParams( null, sender.getAddress(), + null, sender.getAddress(), null, Bytes.EMPTY.toHexString(), @@ -123,6 +124,7 @@ public void passingGasPriceFieldWorks() { new CallParams( null, sender.getAddress(), + null, sender.getAddress(), null, Bytes.EMPTY.toHexString(), @@ -146,6 +148,7 @@ public void passingChainIdFieldWorks() { new CallParams( "0x539", sender.getAddress(), + null, sender.getAddress(), null, Bytes.EMPTY.toHexString(), @@ -169,6 +172,7 @@ public void passingEIP1559FieldsWorks() { new CallParams( null, sender.getAddress(), + null, sender.getAddress(), null, Bytes.EMPTY.toHexString(), @@ -192,6 +196,7 @@ public void passingChainIdAndEIP1559FieldsWorks() { new CallParams( "0x539", sender.getAddress(), + null, sender.getAddress(), null, Bytes.EMPTY.toHexString(), @@ -219,6 +224,7 @@ public void passingStateOverridesWorks() { new CallParams( "0x539", sender.getAddress(), + null, sender.getAddress(), "1", Bytes.EMPTY.toHexString(), @@ -239,6 +245,49 @@ public void passingStateOverridesWorks() { "transaction up-front cost 0x208cbab601 exceeds transaction sender account balance 0x0"); } + @Test + public void passingNonceWorks() { + + final Account sender = accounts.getSecondaryBenefactor(); + + final CallParams callParams = + new CallParams( + null, + sender.getAddress(), + "0", + sender.getAddress(), + null, + Bytes.EMPTY.toHexString(), + "0", + null, + "0x1234", + null); + + final var reqLinea = new LineaEstimateGasRequest(callParams); + final var respLinea = reqLinea.execute(minerNode.nodeRequests()); + assertThat(respLinea.hasError()).isFalse(); + assertThat(respLinea.getResult()).isNotNull(); + + // try with a future nonce + final CallParams callParamsFuture = + new CallParams( + null, + sender.getAddress(), + "10", + sender.getAddress(), + null, + Bytes.EMPTY.toHexString(), + "0", + null, + "0x1234", + null); + + final var reqLineaFuture = new LineaEstimateGasRequest(callParamsFuture); + final var respLineaFuture = reqLineaFuture.execute(minerNode.nodeRequests()); + assertThat(respLineaFuture.hasError()).isFalse(); + assertThat(respLineaFuture.getResult()).isNotNull(); + } + @Test public void lineaEstimateGasIsProfitable() { @@ -259,6 +308,7 @@ public void lineaEstimateGasIsProfitable() { new CallParams( null, sender.getAddress(), + null, sender.getAddress(), null, payload.toHexString(), @@ -320,6 +370,7 @@ public void invalidParametersLineaEstimateGasRequestReturnErrorResponse() { null, sender.getAddress(), null, + null, "", "", String.valueOf(Integer.MAX_VALUE), @@ -341,6 +392,7 @@ public void revertedTransactionReturnErrorResponse() throws Exception { new CallParams( null, sender.getAddress(), + null, simpleStorage.getContractAddress(), "", "", @@ -363,6 +415,7 @@ public void failedTransactionReturnErrorResponse() { null, sender.getAddress(), null, + null, "", Accounts.GENESIS_ACCOUNT_TWO_PRIVATE_KEY, "0", @@ -492,6 +545,7 @@ static class RawEstimateGasResponse extends org.web3j.protocol.core.Response getTestCliOptions() { + return new TestCommandLineOptionsBuilder().build(); + } + + @Test + public void singleTxBundleIsAcceptedAndMined() { + final Account sender = accounts.getSecondaryBenefactor(); + final Account recipient = accounts.getPrimaryBenefactor(); + + final TransferTransaction tx = accountTransactions.createTransfer(sender, recipient, 1); + + final String rawTx = tx.signedTransactionData(); + + final var sendBundleRequest = + new SendBundleRequest(new BundleParams(new String[] {rawTx}, Integer.toHexString(1))); + final var sendBundleResponse = sendBundleRequest.execute(minerNode.nodeRequests()); + + assertThat(sendBundleResponse.hasError()).isFalse(); + assertThat(sendBundleResponse.getResult().bundleHash()).isNotBlank(); + + minerNode.verify(eth.expectSuccessfulTransactionReceipt(tx.transactionHash())); + } + + @Test + public void bundleIsAcceptedAndMined() { + final Account sender = accounts.getSecondaryBenefactor(); + final Account recipient = accounts.getPrimaryBenefactor(); + + final TransferTransaction tx1 = accountTransactions.createTransfer(sender, recipient, 1); + final TransferTransaction tx2 = accountTransactions.createTransfer(recipient, sender, 1); + + final String[] rawTxs = new String[] {tx1.signedTransactionData(), tx2.signedTransactionData()}; + + final var sendBundleRequest = + new SendBundleRequest(new BundleParams(rawTxs, Integer.toHexString(1))); + final var sendBundleResponse = sendBundleRequest.execute(minerNode.nodeRequests()); + + assertThat(sendBundleResponse.hasError()).isFalse(); + assertThat(sendBundleResponse.getResult().bundleHash()).isNotBlank(); + + minerNode.verify(eth.expectSuccessfulTransactionReceipt(tx1.transactionHash())); + minerNode.verify(eth.expectSuccessfulTransactionReceipt(tx2.transactionHash())); + } + + @RequiredArgsConstructor + static class SendBundleRequest implements Transaction { + private final BundleParams bundleParams; + + @Override + public SendBundleResponse execute(final NodeRequests nodeRequests) { + try { + return new Request<>( + "linea_sendBundle", + Arrays.asList(bundleParams), + nodeRequests.getWeb3jService(), + SendBundleResponse.class) + .send(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class SendBundleResponse extends org.web3j.protocol.core.Response {} + + record Response(String bundleHash) {} + } + + record BundleParams(String[] txs, String blockNumber) {} +} diff --git a/acceptance-tests/src/test/resources/log4j2.xml b/acceptance-tests/src/test/resources/log4j2-test.xml similarity index 100% rename from acceptance-tests/src/test/resources/log4j2.xml rename to acceptance-tests/src/test/resources/log4j2-test.xml diff --git a/acceptance-tests/src/test/resources/logback.xml b/acceptance-tests/src/test/resources/logback.xml deleted file mode 100644 index 784d4409c..000000000 --- a/acceptance-tests/src/test/resources/logback.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - %d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n - - - - - - - \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index be182dcf6..9474bfdaf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ releaseVersion=1.2.0-rc3.2 -besuVersion=25.1-delivery45 +besuVersion=25.2-bundles arithmetizationVersion=beta-v1.2.0-rc3 besuArtifactGroup=io.consensys.linea-besu distributionIdentifier=linea-sequencer diff --git a/sequencer/build.gradle b/sequencer/build.gradle index 3c50c919b..e14936638 100644 --- a/sequencer/build.gradle +++ b/sequencer/build.gradle @@ -42,11 +42,12 @@ dependencies { implementation "${besuArtifactGroup}.internal:algorithms" implementation "${besuArtifactGroup}.internal:api" implementation "${besuArtifactGroup}.internal:core" + implementation "${besuArtifactGroup}.internal:eth" implementation "${besuArtifactGroup}.internal:rlp" - implementation 'com.google.code.gson:gson' - implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8' + implementation 'com.github.ben-manes.caffeine:caffeine' + implementation 'com.google.code.gson:gson' implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-units' diff --git a/sequencer/src/main/java/net/consensys/linea/AbstractLineaSharedPrivateOptionsPlugin.java b/sequencer/src/main/java/net/consensys/linea/AbstractLineaSharedPrivateOptionsPlugin.java index dcc98083b..124abd89e 100644 --- a/sequencer/src/main/java/net/consensys/linea/AbstractLineaSharedPrivateOptionsPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/AbstractLineaSharedPrivateOptionsPlugin.java @@ -38,9 +38,11 @@ import net.consensys.linea.rpc.services.BundlePoolService; import net.consensys.linea.rpc.services.LineaLimitedBundlePool; import org.hyperledger.besu.plugin.ServiceManager; +import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; /** @@ -59,11 +61,13 @@ @Slf4j public abstract class AbstractLineaSharedPrivateOptionsPlugin extends AbstractLineaSharedOptionsPlugin { + protected static BesuConfiguration besuConfiguration; protected static BlockchainService blockchainService; protected static MetricsSystem metricsSystem; protected static BesuEvents besuEvents; protected static BundlePoolService bundlePoolService; protected static MetricCategoryRegistry metricCategoryRegistry; + protected static RpcEndpointService rpcEndpointService; private static final AtomicBoolean sharedRegisterTasksDone = new AtomicBoolean(false); private static final AtomicBoolean sharedStartTasksDone = new AtomicBoolean(false); @@ -140,6 +144,13 @@ public synchronized void register(final ServiceManager serviceManager) { } protected static void performSharedRegisterTasksOnce(final ServiceManager serviceManager) { + besuConfiguration = + serviceManager + .getService(BesuConfiguration.class) + .orElseThrow( + () -> + new RuntimeException( + "Failed to obtain BesuConfiguration from the ServiceManager.")); blockchainService = serviceManager .getService(BlockchainService.class) @@ -155,6 +166,14 @@ protected static void performSharedRegisterTasksOnce(final ServiceManager servic () -> new RuntimeException( "Failed to obtain MetricCategoryRegistry from the ServiceManager.")); + + rpcEndpointService = + serviceManager + .getService(RpcEndpointService.class) + .orElseThrow( + () -> + new RuntimeException( + "Failed to obtain RpcEndpointService from the ServiceManager.")); } @Override @@ -196,7 +215,6 @@ private void performSharedStartTasksOnce(final ServiceManager serviceManager) { bundlePoolService = new LineaLimitedBundlePool( transactionSelectorConfiguration().maxBundlePoolSizeBytes(), besuEvents); - serviceManager.addService(BundlePoolService.class, bundlePoolService); } @Override diff --git a/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java b/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java index f43f477c2..f40d51946 100644 --- a/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java @@ -28,25 +28,16 @@ import org.hyperledger.besu.plugin.data.AddedBlockContext; import org.hyperledger.besu.plugin.services.BesuEvents; import org.hyperledger.besu.plugin.services.BesuEvents.InitialSyncCompletionListener; -import org.hyperledger.besu.plugin.services.RpcEndpointService; /** This plugin registers handlers that are activated when new blocks are imported */ @Slf4j @AutoService(BesuPlugin.class) public class LineaExtraDataPlugin extends AbstractLineaRequiredPlugin { private ServiceManager serviceManager; - private RpcEndpointService rpcEndpointService; @Override public void doRegister(final ServiceManager context) { serviceManager = context; - rpcEndpointService = - context - .getService(RpcEndpointService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain RpcEndpointService from the ServiceManager.")); metricCategoryRegistry.addMetricCategory(PRICING_CONF); } diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaCancelBundle.java b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaCancelBundle.java index 454d22183..15cb8fc9e 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaCancelBundle.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaCancelBundle.java @@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j; import net.consensys.linea.rpc.services.BundlePoolService; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; -import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.exception.PluginRpcEndpointException; import org.hyperledger.besu.plugin.services.rpc.PluginRpcRequest; @@ -28,13 +27,8 @@ public class LineaCancelBundle { private static final AtomicInteger LOG_SEQUENCE = new AtomicInteger(); private final JsonRpcParameter parameterParser = new JsonRpcParameter(); - private final RpcEndpointService rpcEndpointService; private BundlePoolService bundlePool; - public LineaCancelBundle(final RpcEndpointService rpcEndpointService) { - this.rpcEndpointService = rpcEndpointService; - } - public LineaCancelBundle init(BundlePoolService bundlePoolService) { this.bundlePool = bundlePoolService; return this; diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaSendBundle.java b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaSendBundle.java index c1c382853..7b300ba03 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaSendBundle.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaSendBundle.java @@ -30,11 +30,10 @@ import org.apache.tuweni.bytes.Bytes; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.PendingTransaction; -import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; import org.hyperledger.besu.ethereum.api.util.DomainObjectDecodeUtils; -import org.hyperledger.besu.plugin.services.RpcEndpointService; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.plugin.services.exception.PluginRpcEndpointException; import org.hyperledger.besu.plugin.services.rpc.PluginRpcRequest; import org.hyperledger.besu.plugin.services.rpc.RpcMethodError; @@ -43,13 +42,8 @@ public class LineaSendBundle { private static final AtomicInteger LOG_SEQUENCE = new AtomicInteger(); private final JsonRpcParameter parameterParser = new JsonRpcParameter(); - private final RpcEndpointService rpcEndpointService; private BundlePoolService bundlePool; - public LineaSendBundle(final RpcEndpointService rpcEndpointService) { - this.rpcEndpointService = rpcEndpointService; - } - public LineaSendBundle init(BundlePoolService bundlePoolService) { this.bundlePool = bundlePoolService; return this; @@ -93,7 +87,7 @@ public BundleResponse execute(final PluginRpcRequest request) { List txs = bundleParams.txs.stream() .map(DomainObjectDecodeUtils::decodeRawTransaction) - .map(tx -> new PendingBundleTx(tx, true, true, System.currentTimeMillis())) + .map(tx -> new PendingBundleTx(tx)) .collect(Collectors.toList()); if (!txs.isEmpty()) { @@ -187,10 +181,16 @@ public BundleParameter( } } - public record PendingBundleTx( - Transaction getTransaction, - boolean isReceivedFromLocalSource, - boolean hasPriority, - long getAddedAt) - implements PendingTransaction {} + public class PendingBundleTx + extends org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.Local { + + public PendingBundleTx(final Transaction transaction) { + super(transaction); + } + + @Override + public String toTraceLog() { + return "Bundle tx: " + super.toTraceLog(); + } + } } diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaEstimateGasEndpointPlugin.java b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaEstimateGasEndpointPlugin.java index 3f9d2f934..64cdf350e 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaEstimateGasEndpointPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaEstimateGasEndpointPlugin.java @@ -23,16 +23,13 @@ import net.consensys.linea.rpc.methods.LineaEstimateGas; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.ServiceManager; -import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; /** Registers RPC endpoints. This class provides RPC endpoints under the 'linea' namespace. */ @AutoService(BesuPlugin.class) @Slf4j public class LineaEstimateGasEndpointPlugin extends AbstractLineaRequiredPlugin { - private BesuConfiguration besuConfiguration; - private RpcEndpointService rpcEndpointService; + private TransactionSimulationService transactionSimulationService; private LineaEstimateGas lineaEstimateGasMethod; @@ -43,22 +40,6 @@ public class LineaEstimateGasEndpointPlugin extends AbstractLineaRequiredPlugin */ @Override public void doRegister(final ServiceManager serviceManager) { - besuConfiguration = - serviceManager - .getService(BesuConfiguration.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BesuConfiguration from the ServiceManager.")); - - rpcEndpointService = - serviceManager - .getService(RpcEndpointService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain RpcEndpointService from the ServiceManager.")); - transactionSimulationService = serviceManager .getService(TransactionSimulationService.class) diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaLimitedBundlePool.java b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaLimitedBundlePool.java index 4672e11a4..bfc28a292 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaLimitedBundlePool.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaLimitedBundlePool.java @@ -241,9 +241,7 @@ private void removeFromBlockIndex(TransactionBundle bundle) { } private int calculateWeight(TransactionBundle bundle) { - return bundle.pendingTransactions().stream() - .mapToInt(pt -> pt.getTransaction().getSize()) - .sum(); + return bundle.pendingTransactions().stream().mapToInt(PendingTransaction::memorySize).sum(); } /** diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSendBundleEndpointPlugin.java b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSendBundleEndpointPlugin.java index 5b3148a4f..c6a78e373 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSendBundleEndpointPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSendBundleEndpointPlugin.java @@ -21,14 +21,11 @@ import net.consensys.linea.rpc.methods.LineaSendBundle; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.ServiceManager; -import org.hyperledger.besu.plugin.services.RpcEndpointService; @AutoService(BesuPlugin.class) public class LineaSendBundleEndpointPlugin extends AbstractLineaRequiredPlugin { - private RpcEndpointService rpcEndpointService; private LineaSendBundle lineaSendBundleMethod; private LineaCancelBundle lineaCancelBundleMethod; - private ServiceManager serviceManager; /** * Register the bundle RPC service. @@ -37,23 +34,15 @@ public class LineaSendBundleEndpointPlugin extends AbstractLineaRequiredPlugin { */ @Override public void doRegister(final ServiceManager serviceManager) { - this.serviceManager = serviceManager; - rpcEndpointService = - serviceManager - .getService(RpcEndpointService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain RpcEndpointService from the ServiceManager.")); - - lineaSendBundleMethod = new LineaSendBundle(rpcEndpointService); + lineaSendBundleMethod = new LineaSendBundle(); rpcEndpointService.registerRPCEndpoint( lineaSendBundleMethod.getNamespace(), lineaSendBundleMethod.getName(), lineaSendBundleMethod::execute); - lineaCancelBundleMethod = new LineaCancelBundle(rpcEndpointService); + lineaCancelBundleMethod = new LineaCancelBundle(); + rpcEndpointService.registerRPCEndpoint( lineaCancelBundleMethod.getNamespace(), lineaCancelBundleMethod.getName(), @@ -68,16 +57,9 @@ public void doRegister(final ServiceManager serviceManager) { @Override public void start() { super.start(); - final var bundlePool = - serviceManager - .getService(BundlePoolService.class) - .orElseThrow( - () -> - new RuntimeException("Failed to obtain Bundle pool from the ServiceManager.")); // set the pool - lineaSendBundleMethod.init(bundlePool); - // set the pool - lineaCancelBundleMethod.init(bundlePool); + lineaSendBundleMethod.init(bundlePoolService); + lineaCancelBundleMethod.init(bundlePoolService); } } diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSetExtraDataEndpointPlugin.java b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSetExtraDataEndpointPlugin.java index b5f913bfb..d38db88de 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSetExtraDataEndpointPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/services/LineaSetExtraDataEndpointPlugin.java @@ -22,13 +22,11 @@ import net.consensys.linea.rpc.methods.LineaSetExtraData; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.ServiceManager; -import org.hyperledger.besu.plugin.services.RpcEndpointService; /** Registers RPC endpoints. This class provides RPC endpoints under the 'linea' namespace. */ @AutoService(BesuPlugin.class) @Slf4j public class LineaSetExtraDataEndpointPlugin extends AbstractLineaRequiredPlugin { - private RpcEndpointService rpcEndpointService; private LineaSetExtraData lineaSetExtraDataMethod; /** @@ -39,14 +37,6 @@ public class LineaSetExtraDataEndpointPlugin extends AbstractLineaRequiredPlugin @Override public void doRegister(final ServiceManager serviceManager) { - rpcEndpointService = - serviceManager - .getService(RpcEndpointService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain RpcEndpointService from the ServiceManager.")); - lineaSetExtraDataMethod = new LineaSetExtraData(rpcEndpointService); rpcEndpointService.registerRPCEndpoint( diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLimitsValidationResult.java b/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLimitsValidationResult.java index ba661cf85..c776831d5 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLimitsValidationResult.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLimitsValidationResult.java @@ -14,10 +14,12 @@ */ package net.consensys.linea.sequencer.modulelimit; +import lombok.EqualsAndHashCode; import lombok.Getter; /** Represents the result of verifying module line counts against their limits. */ @Getter +@EqualsAndHashCode public class ModuleLimitsValidationResult { private final ModuleLineCountValidator.ModuleLineCountResult result; private final String moduleName; diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidator.java index 5009e3ea5..353954594 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidator.java @@ -17,12 +17,11 @@ import java.io.File; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.HashMap; import java.util.Map; +import java.util.function.Function; import java.util.stream.Collectors; import com.google.common.io.Resources; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.config.LineaTracerConfiguration; import org.apache.tuweni.toml.Toml; @@ -30,22 +29,20 @@ import org.apache.tuweni.toml.TomlTable; /** - * Accumulates and verifies line counts for modules based on provided limits. It supports verifying - * if current transactions exceed these limits and updates the accumulated counts. + * Verifies line counts for modules based on provided limits. It supports verifying if current + * transaction exceed these limits. */ @Slf4j public class ModuleLineCountValidator { private final Map moduleLineCountLimits; - @Getter private final Map accumulatedLineCountsPerModule = new HashMap<>(); - /** * Constructs a new accumulator with specified module line count limits. * * @param moduleLineCountLimits A map of module names to their respective line count limits. */ public ModuleLineCountValidator(Map moduleLineCountLimits) { - this.moduleLineCountLimits = new HashMap<>(moduleLineCountLimits); + this.moduleLineCountLimits = Map.copyOf(moduleLineCountLimits); } /** @@ -55,7 +52,23 @@ public ModuleLineCountValidator(Map moduleLineCountLimits) { * counts. * @return A {@link ModuleLimitsValidationResult} indicating the outcome of the verification. */ - public ModuleLimitsValidationResult validate(Map currentAccumulatedLineCounts) { + public ModuleLimitsValidationResult validate( + final Map currentAccumulatedLineCounts) { + return validate(currentAccumulatedLineCounts, initialLineCountLimits()); + } + + /** + * Verifies if the current accumulated line counts, against previous accumulation line counts, for + * modules exceed the predefined limits. + * + * @param currentAccumulatedLineCounts A map of module names to their current accumulated line + * counts. + * @param prevAccumulatedLineCounts A map with previous accumulated line counts. + * @return A {@link ModuleLimitsValidationResult} indicating the outcome of the verification. + */ + public ModuleLimitsValidationResult validate( + final Map currentAccumulatedLineCounts, + final Map prevAccumulatedLineCounts) { for (Map.Entry moduleEntry : currentAccumulatedLineCounts.entrySet()) { String moduleName = moduleEntry.getKey(); Integer currentTotalLineCountForModule = moduleEntry.getValue(); @@ -66,10 +79,8 @@ public ModuleLimitsValidationResult validate(Map currentAccumul return ModuleLimitsValidationResult.moduleNotDefined(moduleName); } - int previouslyAccumulatedLineCount = - accumulatedLineCountsPerModule.getOrDefault(moduleName, 0); - int lineCountAddedByCurrentTx = - currentTotalLineCountForModule - previouslyAccumulatedLineCount; + final int lineCountAddedByCurrentTx = + currentTotalLineCountForModule - prevAccumulatedLineCounts.get(moduleName); if (lineCountAddedByCurrentTx > lineCountLimitForModule) { return ModuleLimitsValidationResult.txModuleLineCountOverflow( @@ -92,14 +103,9 @@ public ModuleLimitsValidationResult validate(Map currentAccumul return ModuleLimitsValidationResult.VALID; } - /** - * Updates the internal map of accumulated line counts per module. - * - * @param newAccumulatedLineCounts A map of module names to their new accumulated line counts. - */ - public void updateAccumulatedLineCounts(Map newAccumulatedLineCounts) { - accumulatedLineCountsPerModule.clear(); - accumulatedLineCountsPerModule.putAll(newAccumulatedLineCounts); + private Map initialLineCountLimits() { + return moduleLineCountLimits.keySet().stream() + .collect(Collectors.toMap(Function.identity(), unused -> 0)); } /** Enumerates possible outcomes of verifying module line counts against their limits. */ 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 f20e93500..98c48fc4d 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 @@ -35,7 +35,6 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.ServiceManager; -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; @@ -51,7 +50,6 @@ @AutoService(BesuPlugin.class) public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPlugin { private ServiceManager serviceManager; - private BesuConfiguration besuConfiguration; private TransactionPoolValidatorService transactionPoolValidatorService; private TransactionSimulationService transactionSimulationService; private Optional rejectedTxJsonRpcManager = Optional.empty(); @@ -59,13 +57,6 @@ public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPl @Override public void doRegister(final ServiceManager serviceManager) { this.serviceManager = serviceManager; - besuConfiguration = - serviceManager - .getService(BesuConfiguration.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BesuConfiguration from the ServiceManager.")); transactionPoolValidatorService = serviceManager diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactory.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactory.java index 2dcf635d0..c7224f586 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactory.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactory.java @@ -49,7 +49,7 @@ public class LineaTransactionSelectorFactory implements PluginTransactionSelecto private final LineaProfitabilityConfiguration profitabilityConfiguration; private final LineaTracerConfiguration tracerConfiguration; private final Optional maybeProfitabilityMetrics; - private final Optional maybeBundlePool; + private final BundlePoolService bundlePoolService; private final long maxBundleGasPerBlock; private final Map limitsMap; @@ -63,7 +63,7 @@ public LineaTransactionSelectorFactory( final Map limitsMap, final Optional rejectedTxJsonRpcManager, final Optional maybeProfitabilityMetrics, - final Optional maybeBundlePool, + final BundlePoolService bundlePoolService, final long maxBundleGasPerBlock) { this.blockchainService = blockchainService; this.txSelectorConfiguration = txSelectorConfiguration; @@ -73,19 +73,20 @@ public LineaTransactionSelectorFactory( this.limitsMap = limitsMap; this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager; this.maybeProfitabilityMetrics = maybeProfitabilityMetrics; - this.maybeBundlePool = maybeBundlePool; + this.bundlePoolService = bundlePoolService; this.maxBundleGasPerBlock = maxBundleGasPerBlock; } @Override public PluginTransactionSelector create(final SelectorsStateManager selectorsStateManager) { return new LineaTransactionSelector( + selectorsStateManager, blockchainService, txSelectorConfiguration, l1L2BridgeConfiguration, profitabilityConfiguration, tracerConfiguration, - maybeBundlePool, + bundlePoolService, limitsMap, rejectedTxJsonRpcManager, maybeProfitabilityMetrics); @@ -94,40 +95,39 @@ public PluginTransactionSelector create(final SelectorsStateManager selectorsSta public void selectPendingTransactions( final BlockTransactionSelectionService bts, final ProcessableBlockHeader pendingBlockHeader) { final AtomicLong cumulativeBundleGasLimit = new AtomicLong(0L); - maybeBundlePool.ifPresent( - bp -> - bp.getBundlesByBlockNumber(pendingBlockHeader.getNumber()) - .forEach( - bundle -> { - // mark as "to-evaluate" to prevent eviction during processing: - bp.markBundleForEval(bundle); - var badBundleRes = - bundle.pendingTransactions().stream() - .map( - pt -> { - // restricting block bundles on the basis of gasLimit, not gas - // used. gasUsed isn't returned from evaluatePendingTransaction - // currently - final var pendingGasLimit = pt.getTransaction().getGasLimit(); - if (pendingGasLimit + cumulativeBundleGasLimit.get() - < maxBundleGasPerBlock) { - var res = bts.evaluatePendingTransaction(pt); - if (res.selected()) { - cumulativeBundleGasLimit.addAndGet(pendingGasLimit); - } - return res; - } else { - return TransactionSelectionResult - .BLOCK_OCCUPANCY_ABOVE_THRESHOLD; - } - }) - .filter(evalRes -> !evalRes.selected()) - .findFirst(); - if (badBundleRes.isPresent()) { - bts.rollback(); - } else { - bts.commit(); - } - })); + + bundlePoolService + .getBundlesByBlockNumber(pendingBlockHeader.getNumber()) + .forEach( + bundle -> { + // mark as "to-evaluate" to prevent eviction during processing: + bundlePoolService.markBundleForEval(bundle); + var badBundleRes = + bundle.pendingTransactions().stream() + .map( + pt -> { + // restricting block bundles on the basis of gasLimit, not gas + // used. gasUsed isn't returned from evaluatePendingTransaction + // currently + final var pendingGasLimit = pt.getTransaction().getGasLimit(); + if (pendingGasLimit + cumulativeBundleGasLimit.get() + < maxBundleGasPerBlock) { + var res = bts.evaluatePendingTransaction(pt); + if (res.selected()) { + cumulativeBundleGasLimit.addAndGet(pendingGasLimit); + } + return res; + } else { + return TransactionSelectionResult.BLOCK_OCCUPANCY_ABOVE_THRESHOLD; + } + }) + .filter(evalRes -> !evalRes.selected()) + .findFirst(); + if (badBundleRes.isPresent()) { + bts.rollback(); + } else { + bts.commit(); + } + }); } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorPlugin.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorPlugin.java index 46d4e4149..d071bd6af 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorPlugin.java @@ -28,11 +28,9 @@ import net.consensys.linea.config.LineaTransactionSelectorConfiguration; import net.consensys.linea.jsonrpc.JsonRpcManager; import net.consensys.linea.metrics.HistogramMetrics; -import net.consensys.linea.rpc.services.BundlePoolService; import net.consensys.linea.sequencer.txselection.selectors.ProfitableTransactionSelector; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.ServiceManager; -import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.TransactionSelectionService; /** @@ -43,20 +41,14 @@ @Slf4j @AutoService(BesuPlugin.class) public class LineaTransactionSelectorPlugin extends AbstractLineaRequiredPlugin { - public static final String NAME = "linea"; - private ServiceManager serviceManager; private TransactionSelectionService transactionSelectionService; private Optional rejectedTxJsonRpcManager = Optional.empty(); - private BesuConfiguration besuConfiguration; - private Optional bundlePool = Optional.empty(); // initialize to the static config default: private long maxBundleGasPerBlock = DEFAULT_MAX_BUNDLE_GAS_PER_BLOCK; @Override public void doRegister(final ServiceManager serviceManager) { - this.serviceManager = serviceManager; - transactionSelectionService = serviceManager .getService(TransactionSelectionService.class) @@ -65,14 +57,6 @@ public void doRegister(final ServiceManager serviceManager) { new RuntimeException( "Failed to obtain TransactionSelectionService from the ServiceManager.")); - besuConfiguration = - serviceManager - .getService(BesuConfiguration.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BesuConfiguration from the ServiceManager.")); - metricCategoryRegistry.addMetricCategory(SEQUENCER_PROFITABILITY); } @@ -83,9 +67,6 @@ public void start() { final LineaTransactionSelectorConfiguration txSelectorConfiguration = transactionSelectorConfiguration(); - // fetch bundle pool service, if configured: - bundlePool = serviceManager.getService(BundlePoolService.class); - // set maxBundleGasPerBlock maxBundleGasPerBlock = txSelectorConfiguration.maxGasPerBlock(); @@ -123,7 +104,7 @@ public void start() { createLimitModules(tracerConfiguration()), rejectedTxJsonRpcManager, maybeProfitabilityMetrics, - bundlePool, + bundlePoolService, maxBundleGasPerBlock)); } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelector.java index 67930230e..0d639961e 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelector.java @@ -23,7 +23,6 @@ import net.consensys.linea.rpc.methods.LineaSendBundle; import net.consensys.linea.rpc.services.BundlePoolService; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; @@ -39,7 +38,7 @@ public LineaSendBundleTransactionSelector(BundlePoolService bundlePool) { @Override public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext txContext) { + final TransactionEvaluationContext txContext) { // short circuit if we are not a PendingBundleTx if (!(txContext.getPendingTransaction() instanceof LineaSendBundle.PendingBundleTx)) { @@ -81,7 +80,7 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext txContext, + final TransactionEvaluationContext txContext, final TransactionProcessingResult transactionProcessingResult) { // short circuit if we are not a PendingBundleTx diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaTransactionSelector.java index db5582a56..1de9d71cb 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/LineaTransactionSelector.java @@ -18,7 +18,6 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_MODULE_LINE_COUNT_OVERFLOW_CACHED; import java.time.Instant; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -34,12 +33,12 @@ import net.consensys.linea.metrics.HistogramMetrics; import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration; import net.consensys.linea.rpc.services.BundlePoolService; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; /** Class for transaction selection using a list of selectors. */ @@ -52,12 +51,13 @@ public class LineaTransactionSelector implements PluginTransactionSelector { private final Set rejectedTransactionReasonsMap = new HashSet<>(); public LineaTransactionSelector( + final SelectorsStateManager selectorsStateManager, final BlockchainService blockchainService, final LineaTransactionSelectorConfiguration txSelectorConfiguration, final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, final LineaProfitabilityConfiguration profitabilityConfiguration, final LineaTracerConfiguration tracerConfiguration, - final Optional maybeBundlePool, + final BundlePoolService bundlePoolService, final Map limitsMap, final Optional rejectedTxJsonRpcManager, final Optional maybeProfitabilityMetrics) { @@ -71,12 +71,13 @@ public LineaTransactionSelector( selectors = createTransactionSelectors( + selectorsStateManager, blockchainService, txSelectorConfiguration, l1L2BridgeConfiguration, profitabilityConfiguration, tracerConfiguration, - maybeBundlePool, + bundlePoolService, limitsMap, maybeProfitabilityMetrics); } @@ -84,27 +85,30 @@ public LineaTransactionSelector( /** * Creates a list of selectors based on Linea configuration. * + * @param selectorsStateManager * @param blockchainService Blockchain service. * @param txSelectorConfiguration The configuration to use. * @param profitabilityConfiguration The profitability configuration. * @param tracerConfiguration the tracer config - * @param maybeBundlePool an optional bundle pool for transaction bundle selector + * @param bundlePoolService bundle pool for transaction bundle selector * @param limitsMap The limits map. * @param maybeProfitabilityMetrics The optional profitability metrics * @return A list of selectors. */ private List createTransactionSelectors( + final SelectorsStateManager selectorsStateManager, final BlockchainService blockchainService, final LineaTransactionSelectorConfiguration txSelectorConfiguration, final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, final LineaProfitabilityConfiguration profitabilityConfiguration, final LineaTracerConfiguration tracerConfiguration, - final Optional maybeBundlePool, + final BundlePoolService bundlePoolService, final Map limitsMap, final Optional maybeProfitabilityMetrics) { traceLineLimitTransactionSelector = new TraceLineLimitTransactionSelector( + selectorsStateManager, blockchainService.getChainId().get(), limitsMap, txSelectorConfiguration, @@ -112,20 +116,18 @@ private List createTransactionSelectors( tracerConfiguration); List selectors = - new ArrayList<>( - List.of( - new MaxBlockCallDataTransactionSelector( - txSelectorConfiguration.maxBlockCallDataSize()), - new MaxBlockGasTransactionSelector(txSelectorConfiguration.maxGasPerBlock()), - new ProfitableTransactionSelector( - blockchainService, - txSelectorConfiguration, - profitabilityConfiguration, - maybeProfitabilityMetrics), - traceLineLimitTransactionSelector)); - - maybeBundlePool.ifPresent( - bundlePool -> selectors.add(new LineaSendBundleTransactionSelector(bundlePool))); + List.of( + new MaxBlockCallDataTransactionSelector( + selectorsStateManager, txSelectorConfiguration.maxBlockCallDataSize()), + new MaxBlockGasTransactionSelector( + selectorsStateManager, txSelectorConfiguration.maxGasPerBlock()), + new ProfitableTransactionSelector( + blockchainService, + txSelectorConfiguration, + profitabilityConfiguration, + maybeProfitabilityMetrics), + new LineaSendBundleTransactionSelector(bundlePoolService), + traceLineLimitTransactionSelector); return selectors; } @@ -139,7 +141,7 @@ private List createTransactionSelectors( */ @Override public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext evaluationContext) { + final TransactionEvaluationContext evaluationContext) { return selectors.stream() .map(selector -> selector.evaluateTransactionPreProcessing(evaluationContext)) .filter(result -> !result.equals(TransactionSelectionResult.SELECTED)) @@ -157,7 +159,7 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( */ @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { for (var selector : selectors) { TransactionSelectionResult result = @@ -177,7 +179,7 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( */ @Override public void onTransactionSelected( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { selectors.forEach( selector -> selector.onTransactionSelected(evaluationContext, processingResult)); @@ -191,7 +193,7 @@ public void onTransactionSelected( */ @Override public void onTransactionNotSelected( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionSelectionResult transactionSelectionResult) { selectors.forEach( selector -> diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataTransactionSelector.java index 473629b04..a1472ee08 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataTransactionSelector.java @@ -17,13 +17,12 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.BLOCK_CALLDATA_OVERFLOW; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; -import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.AbstractStatefulPluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; /** @@ -32,11 +31,16 @@ * pushes the call data size of the block over the limit. */ @Slf4j -@RequiredArgsConstructor -public class MaxBlockCallDataTransactionSelector implements PluginTransactionSelector { +public class MaxBlockCallDataTransactionSelector + extends AbstractStatefulPluginTransactionSelector { private final int maxBlockCallDataSize; - private int cumulativeBlockCallDataSize; + + public MaxBlockCallDataTransactionSelector( + final SelectorsStateManager stateManager, final int maxBlockCallDataSize) { + super(stateManager, 0L, SelectorsStateManager.StateDuplicator::duplicateLong); + this.maxBlockCallDataSize = maxBlockCallDataSize; + } /** * Evaluates a transaction before processing. Checks if adding the transaction to the block pushes @@ -48,17 +52,22 @@ public class MaxBlockCallDataTransactionSelector implements PluginTransactionSel */ @Override public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext evaluationContext) { + final TransactionEvaluationContext evaluationContext) { final Transaction transaction = evaluationContext.getPendingTransaction().getTransaction(); final int transactionCallDataSize = transaction.getPayload().size(); - if (isTransactionExceedingBlockCallDataSizeLimit(transactionCallDataSize)) { + final var stateCumulativeBlockCallDataSize = getWorkingState(); + + final long newCumulativeBlockCallDataSize = + Math.addExact(stateCumulativeBlockCallDataSize, transactionCallDataSize); + + if (newCumulativeBlockCallDataSize > maxBlockCallDataSize) { log.atTrace() .setMessage( "Cumulative block calldata size including tx {} is {} greater than the max allowed {}, skipping tx") .addArgument(transaction::getHash) - .addArgument(() -> cumulativeBlockCallDataSize + transactionCallDataSize) + .addArgument(newCumulativeBlockCallDataSize) .addArgument(maxBlockCallDataSize) .log(); return BLOCK_CALLDATA_OVERFLOW; @@ -67,39 +76,12 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( log.atTrace() .setMessage("Cumulative block calldata size including tx {} is {}") .addArgument(transaction::getHash) - .addArgument(cumulativeBlockCallDataSize) + .addArgument(newCumulativeBlockCallDataSize) .log(); return SELECTED; } - /** - * Checks if the total call data size of all transactions in a block would exceed the maximum - * allowed size if the given transaction were added. - * - * @param transactionCallDataSize The call data size of the transaction. - * @return true if the total call data size would be too big, false otherwise. - */ - private boolean isTransactionExceedingBlockCallDataSizeLimit(int transactionCallDataSize) { - return Math.addExact(cumulativeBlockCallDataSize, transactionCallDataSize) - > maxBlockCallDataSize; - } - - /** - * Updates the total call data size of all transactions in a block when a transaction is selected. - * - * @param pendingTransaction The selected transaction. - */ - @Override - public void onTransactionSelected( - final TransactionEvaluationContext evaluationContext, - final TransactionProcessingResult transactionProcessingResult) { - final int transactionCallDataSize = - evaluationContext.getPendingTransaction().getTransaction().getPayload().size(); - cumulativeBlockCallDataSize = - Math.addExact(cumulativeBlockCallDataSize, transactionCallDataSize); - } - /** * No evaluation is performed post-processing. * @@ -109,9 +91,15 @@ public void onTransactionSelected( */ @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { - // Evaluation done in pre-processing, no action needed here. + final long newCumulativeBlockCallDataSize = + Math.addExact( + getWorkingState(), + evaluationContext.getPendingTransaction().getTransaction().getPayload().size()); + + setWorkingState(newCumulativeBlockCallDataSize); + return SELECTED; } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelector.java index 6e5abab41..1c4229ca4 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelector.java @@ -18,13 +18,12 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_USER_GAS; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; -import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.AbstractStatefulPluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; /** @@ -34,11 +33,23 @@ * configure a max gas per block that is below the limit defined by the protocol. */ @Slf4j -@RequiredArgsConstructor -public class MaxBlockGasTransactionSelector implements PluginTransactionSelector { +public class MaxBlockGasTransactionSelector + extends AbstractStatefulPluginTransactionSelector { private final long maxGasPerBlock; - private long cumulativeBlockGasUsed; + + public MaxBlockGasTransactionSelector( + final SelectorsStateManager selectorsStateManager, final long maxGasPerBlock) { + super(selectorsStateManager, 0L, SelectorsStateManager.StateDuplicator::duplicateLong); + this.maxGasPerBlock = maxGasPerBlock; + } + + @Override + public TransactionSelectionResult evaluateTransactionPreProcessing( + final TransactionEvaluationContext evaluationContext) { + // Evaluation done in post-processing, no action needed here. + return SELECTED; + } /** * Evaluates a transaction post-processing. Checks if adding the gas used of the transaction, to @@ -52,7 +63,7 @@ public class MaxBlockGasTransactionSelector implements PluginTransactionSelector */ @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { final Transaction transaction = evaluationContext.getPendingTransaction().getTransaction(); @@ -70,48 +81,25 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( return TX_GAS_EXCEEDS_USER_MAX_BLOCK_GAS; } - if (isTransactionExceedingMaxBlockGasLimit(gasUsedByTransaction)) { + final var stateCumulativeBlockGasUsed = getWorkingState(); + + final long newCumulativeBlockGasUsed = + Math.addExact(stateCumulativeBlockGasUsed, gasUsedByTransaction); + + if (newCumulativeBlockGasUsed > maxGasPerBlock) { log.atTrace() .setMessage( "Not selecting transaction {}, its cumulative block gas used {} greater than max user gas per block {}," + " skipping it") .addArgument(transaction::getHash) - .addArgument(cumulativeBlockGasUsed) + .addArgument(newCumulativeBlockGasUsed) .addArgument(maxGasPerBlock) .log(); return TX_TOO_LARGE_FOR_REMAINING_USER_GAS; } - return SELECTED; - } - - private boolean isTransactionExceedingMaxBlockGasLimit(long transactionGasUsed) { - try { - return Math.addExact(cumulativeBlockGasUsed, transactionGasUsed) > maxGasPerBlock; - } catch (final ArithmeticException e) { - // Overflow won't occur as cumulativeBlockGasUsed won't exceed Long.MAX_VALUE - return true; - } - } - /** - * If the transaction has been selected, then we add its gas used to the current gas used of the - * block. - * - * @param evaluationContext The current selection context - * @param processingResult The result of processing the selected transaction. - */ - @Override - public void onTransactionSelected( - final TransactionEvaluationContext evaluationContext, - final TransactionProcessingResult processingResult) { - cumulativeBlockGasUsed = - Math.addExact(cumulativeBlockGasUsed, processingResult.getEstimateGasUsedByTransaction()); - } + setWorkingState(newCumulativeBlockGasUsed); - @Override - public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext evaluationContext) { - // Evaluation done in post-processing, no action needed here. return SELECTED; } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/ProfitableTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/ProfitableTransactionSelector.java index 75c9518d5..03cbc4766 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/ProfitableTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/ProfitableTransactionSelector.java @@ -34,7 +34,6 @@ import net.consensys.linea.metrics.HistogramMetrics; import net.consensys.linea.metrics.HistogramMetrics.LabelValue; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; @@ -138,7 +137,7 @@ public ProfitableTransactionSelector( */ @Override public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext evaluationContext) { + final TransactionEvaluationContext evaluationContext) { final Wei minGasPrice = evaluationContext.getMinGasPrice(); @@ -198,7 +197,7 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( */ @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { if (!evaluationContext.getPendingTransaction().hasPriority()) { @@ -240,7 +239,7 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( */ @Override public void onTransactionSelected( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { unprofitableCache.remove(evaluationContext.getPendingTransaction().getTransaction().getHash()); } @@ -254,7 +253,7 @@ public void onTransactionSelected( */ @Override public void onTransactionNotSelected( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionSelectionResult transactionSelectionResult) { final var txHash = evaluationContext.getPendingTransaction().getTransaction().getHash(); if (transactionSelectionResult.discard()) { @@ -276,7 +275,7 @@ private void rememberUnprofitable(final Transaction transaction) { private void updateMetric( final Phase label, - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final Transaction tx, final Wei profitablePriorityFeePerGas) { diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelector.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelector.java index ed7f0675c..540d7bda3 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelector.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelector.java @@ -23,6 +23,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import com.google.common.annotations.VisibleForTesting; @@ -35,14 +36,14 @@ import net.consensys.linea.zktracer.ZkTracer; import net.consensys.linea.zktracer.container.module.Module; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer; -import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.AbstractStatefulPluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; import org.slf4j.Marker; import org.slf4j.MarkerFactory; @@ -53,7 +54,8 @@ * adding a transaction to the block pushes the trace lines for a module over the limit. */ @Slf4j -public class TraceLineLimitTransactionSelector implements PluginTransactionSelector { +public class TraceLineLimitTransactionSelector + extends AbstractStatefulPluginTransactionSelector> { private static final Marker BLOCK_LINE_COUNT_MARKER = MarkerFactory.getMarker("BLOCK_LINE_COUNT"); @VisibleForTesting protected static Set overLineCountLimitCache = new LinkedHashSet<>(); private final ZkTracer zkTracer; @@ -61,15 +63,20 @@ public class TraceLineLimitTransactionSelector implements PluginTransactionSelec private final String limitFilePath; private final Map moduleLimits; private final int overLimitCacheSize; - private final ModuleLineCountValidator moduleLineCountAccumulator; - private Map currCumulatedLineCount; + private final ModuleLineCountValidator moduleLineCountValidator; public TraceLineLimitTransactionSelector( + final SelectorsStateManager stateManager, final BigInteger chainId, final Map moduleLimits, final LineaTransactionSelectorConfiguration txSelectorConfiguration, final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, final LineaTracerConfiguration tracerConfiguration) { + super( + stateManager, + moduleLimits.keySet().stream().collect(Collectors.toMap(Function.identity(), unused -> 0)), + Map::copyOf); + if (l1L2BridgeConfiguration.isEmpty()) { log.error("L1L2 bridge settings have not been defined."); System.exit(1); @@ -88,7 +95,7 @@ public TraceLineLimitTransactionSelector( } } zkTracer.traceStartConflation(1L); - moduleLineCountAccumulator = new ModuleLineCountValidator(moduleLimits); + moduleLineCountValidator = new ModuleLineCountValidator(moduleLimits); } /** @@ -99,7 +106,7 @@ public TraceLineLimitTransactionSelector( */ @Override public TransactionSelectionResult evaluateTransactionPreProcessing( - final TransactionEvaluationContext evaluationContext) { + final TransactionEvaluationContext evaluationContext) { if (overLineCountLimitCache.contains( evaluationContext.getPendingTransaction().getTransaction().getHash())) { log.atTrace() @@ -114,18 +121,11 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( @Override public void onTransactionNotSelected( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionSelectionResult transactionSelectionResult) { zkTracer.popTransaction(evaluationContext.getPendingTransaction()); } - @Override - public void onTransactionSelected( - final TransactionEvaluationContext evaluationContext, - final TransactionProcessingResult processingResult) { - moduleLineCountAccumulator.updateAccumulatedLineCounts(currCumulatedLineCount); - } - /** * Checking the created trace lines is performed post-processing. * @@ -137,20 +137,22 @@ public void onTransactionSelected( */ @Override public TransactionSelectionResult evaluateTransactionPostProcessing( - final TransactionEvaluationContext evaluationContext, + final TransactionEvaluationContext evaluationContext, final TransactionProcessingResult processingResult) { + final var prevCumulatedLineCountMap = getWorkingState(); + // check that we are not exceeding line number for any module - currCumulatedLineCount = zkTracer.getModulesLineCount(); + final var newCumulatedLineCountMap = zkTracer.getModulesLineCount(); final Transaction transaction = evaluationContext.getPendingTransaction().getTransaction(); log.atTrace() .setMessage("Tx {} line count per module: {}") .addArgument(transaction::getHash) - .addArgument(this::logTxLineCount) + .addArgument(() -> logTxLineCount(newCumulatedLineCountMap, prevCumulatedLineCountMap)) .log(); ModuleLimitsValidationResult result = - moduleLineCountAccumulator.validate(currCumulatedLineCount); + moduleLineCountValidator.validate(newCumulatedLineCountMap, prevCumulatedLineCountMap); switch (result.getResult()) { case MODULE_NOT_DEFINED: @@ -178,6 +180,9 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( default: break; } + + setWorkingState(newCumulatedLineCountMap); + return SELECTED; } @@ -201,17 +206,16 @@ private void rememberOverLineCountLimitTransaction(final Transaction transaction .log(); } - private String logTxLineCount() { + private String logTxLineCount( + final Map currCumulatedLineCount, + final Map stateLineLimitMap) { return currCumulatedLineCount.entrySet().stream() .map( e -> // tx line count / cumulated line count / line count limit e.getKey() + "=" - + (e.getValue() - - moduleLineCountAccumulator - .getAccumulatedLineCountsPerModule() - .getOrDefault(e.getKey(), 0)) + + (e.getValue() - stateLineLimitMap.getOrDefault(e.getKey(), 0)) + "/" + e.getValue() + "/" @@ -234,7 +238,7 @@ public void traceEndBlock(final BlockHeader blockHeader, final BlockBody blockBo .addKeyValue( "traceCounts", () -> - moduleLineCountAccumulator.getAccumulatedLineCountsPerModule().entrySet().stream() + getCommitedState().entrySet().stream() .sorted(Map.Entry.comparingByKey()) .map(e -> '"' + e.getKey() + "\":" + e.getValue()) .collect(Collectors.joining(","))) diff --git a/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaCancelBundleTest.java b/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaCancelBundleTest.java index 5d6af3742..0aeac09e3 100644 --- a/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaCancelBundleTest.java +++ b/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaCancelBundleTest.java @@ -24,7 +24,6 @@ import java.util.UUID; import net.consensys.linea.rpc.services.LineaLimitedBundlePool; -import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.exception.PluginRpcEndpointException; import org.hyperledger.besu.plugin.services.rpc.PluginRpcRequest; import org.junit.jupiter.api.BeforeEach; @@ -33,16 +32,14 @@ class LineaCancelBundleTest { private LineaCancelBundle lineaCancelBundle; - private RpcEndpointService rpcEndpointService; private LineaLimitedBundlePool bundlePool; private PluginRpcRequest request; @BeforeEach void setup() { - rpcEndpointService = mock(RpcEndpointService.class); bundlePool = mock(LineaLimitedBundlePool.class); request = mock(PluginRpcRequest.class); - lineaCancelBundle = new LineaCancelBundle(rpcEndpointService).init(bundlePool); + lineaCancelBundle = new LineaCancelBundle().init(bundlePool); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaSendBundleTest.java b/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaSendBundleTest.java index acc7b5814..9fac097ff 100644 --- a/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaSendBundleTest.java +++ b/sequencer/src/test/java/net/consensys/linea/rpc/methods/LineaSendBundleTest.java @@ -34,7 +34,6 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.plugin.services.BesuEvents; -import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.rpc.PluginRpcRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -42,7 +41,6 @@ class LineaSendBundleTest { private LineaSendBundle lineaSendBundle; - private RpcEndpointService rpcEndpointService; private BesuEvents mockEvents; private LineaLimitedBundlePool bundlePool; @@ -60,10 +58,9 @@ class LineaSendBundleTest { @BeforeEach void setup() { - rpcEndpointService = mock(RpcEndpointService.class); mockEvents = mock(BesuEvents.class); bundlePool = spy(new LineaLimitedBundlePool(4096L, mockEvents)); - lineaSendBundle = new LineaSendBundle(rpcEndpointService).init(bundlePool); + lineaSendBundle = new LineaSendBundle().init(bundlePool); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidatorTest.java new file mode 100644 index 000000000..1e711ae82 --- /dev/null +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/modulelimit/ModuleLineCountValidatorTest.java @@ -0,0 +1,67 @@ +/* + * 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.modulelimit; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +class ModuleLineCountValidatorTest { + + @Test + void successfulValidation() { + final var moduleLineCountValidator = + new ModuleLineCountValidator(Map.of("MOD1", 1, "MOD2", 2, "MOD3", 3)); + final var lineCountTx = Map.of("MOD1", 1, "MOD2", 1, "MOD3", 1); + + assertThat(moduleLineCountValidator.validate(lineCountTx)) + .isEqualTo(ModuleLimitsValidationResult.VALID); + } + + @Test + void failedValidationTransactionOverLimit() { + final var moduleLineCountValidator = + new ModuleLineCountValidator(Map.of("MOD1", 1, "MOD2", 2, "MOD3", 3)); + final var lineCountTx = Map.of("MOD1", 3, "MOD2", 2, "MOD3", 3); + + assertThat(moduleLineCountValidator.validate(lineCountTx)) + .isEqualTo(ModuleLimitsValidationResult.txModuleLineCountOverflow("MOD1", 3, 1, 3, 1)); + } + + @Test + void failedValidationBlockOverLimit() { + final var moduleLineCountValidator = + new ModuleLineCountValidator(Map.of("MOD1", 1, "MOD2", 2, "MOD3", 3)); + final var prevLineCountTx = Map.of("MOD1", 1, "MOD2", 1, "MOD3", 1); + + final var lineCountTx = Map.of("MOD1", 1, "MOD2", 3, "MOD3", 3); + + assertThat(moduleLineCountValidator.validate(lineCountTx, prevLineCountTx)) + .isEqualTo(ModuleLimitsValidationResult.blockModuleLineCountFull("MOD2", 2, 2, 3, 2)); + } + + @Test + void failedValidationModuleNotFound() { + final var moduleLineCountValidator = + new ModuleLineCountValidator(Map.of("MOD1", 1, "MOD2", 2, "MOD3", 3)); + + final var lineCountTx = Map.of("MOD4", 1, "MOD2", 1, "MOD3", 1); + + assertThat(moduleLineCountValidator.validate(lineCountTx, lineCountTx)) + .isEqualTo(ModuleLimitsValidationResult.moduleNotDefined("MOD4")); + } +} diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactoryTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactoryTest.java index 1a4419f56..a35743f08 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactoryTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/LineaTransactionSelectorFactoryTest.java @@ -16,8 +16,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -64,7 +62,7 @@ class LineaTransactionSelectorFactoryTest { private Map mockLimitsMap; private BesuEvents mockEvents; private LineaLimitedBundlePool bundlePool; - private Optional mockBundlePool; + private BundlePoolService mockBundlePool; private LineaTransactionSelectorFactory factory; @@ -78,7 +76,6 @@ void setUp() { mockLimitsMap = new HashMap<>(); mockEvents = mock(BesuEvents.class); bundlePool = spy(new LineaLimitedBundlePool(4096, mockEvents)); - mockBundlePool = spy(Optional.of(bundlePool)); factory = new LineaTransactionSelectorFactory( @@ -90,7 +87,7 @@ void setUp() { mockLimitsMap, Optional.empty(), Optional.empty(), - mockBundlePool, + bundlePool, 15_000_000L); } @@ -135,8 +132,6 @@ void testSelectPendingTransactions_WithoutBundles() { var mockPendingBlockHeader = mock(ProcessableBlockHeader.class); when(mockPendingBlockHeader.getNumber()).thenReturn(1L); - doNothing().when(mockBundlePool).ifPresent(any()); - doAnswer(__ -> Optional.empty()).when(mockBundlePool).map(any()); factory.selectPendingTransactions(mockBts, mockPendingBlockHeader); verifyNoInteractions(mockBts); diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelectorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelectorTest.java index 361719583..1065f6268 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelectorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/LineaSendBundleTransactionSelectorTest.java @@ -28,7 +28,6 @@ import net.consensys.linea.rpc.services.BundlePoolService.TransactionBundle; import net.consensys.linea.rpc.services.LineaLimitedBundlePool; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; @@ -124,7 +123,7 @@ private TransactionBundle createBundle(long blockNumber, Long minTimestamp, Long Optional.empty()); } - private TransactionEvaluationContext mockTransactionEvaluationContext( + private TransactionEvaluationContext mockTransactionEvaluationContext( BlockHeader blockHeader, PendingBundleTx pendingTransaction) { return new TestTransactionEvaluationContext(blockHeader, pendingTransaction, Wei.ONE, Wei.ONE); } diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataSizeTransactionSelectorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataSizeTransactionSelectorTest.java index 95933275a..3db536f41 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataSizeTransactionSelectorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockCallDataSizeTransactionSelectorTest.java @@ -21,12 +21,15 @@ import static org.mockito.Mockito.when; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,64 +37,76 @@ public class MaxBlockCallDataSizeTransactionSelectorTest { private static final int BLOCK_CALL_DATA_MAX_SIZE = 100; private static final int BLOCK_CALL_DATA_HALF_SIZE = 50; private static final int TX_CALL_DATA_SIZE = BLOCK_CALL_DATA_HALF_SIZE + 1; + private static int seq = 1; private PluginTransactionSelector transactionSelector; + private SelectorsStateManager selectorsStateManager; @BeforeEach public void initialize() { - transactionSelector = new MaxBlockCallDataTransactionSelector(BLOCK_CALL_DATA_MAX_SIZE); + selectorsStateManager = new SelectorsStateManager(); + transactionSelector = + new MaxBlockCallDataTransactionSelector(selectorsStateManager, BLOCK_CALL_DATA_MAX_SIZE); + selectorsStateManager.blockSelectionStarted(); } @Test public void shouldSelectTransactionWhen_BlockCallDataSize_IsLessThan_MaxBlockCallDataSize() { - var mockTransaction = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); - var mockTransaction2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE - 1); - verifyTransactionSelection(transactionSelector, mockTransaction, SELECTED); - verifyTransactionSelection(transactionSelector, mockTransaction2, SELECTED); + final var evaluationContext1 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext1, SELECTED); + + final var evaluationContext2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE - 1); + verifyTransactionSelection(transactionSelector, evaluationContext2, SELECTED); } @Test public void shouldSelectTransactionWhen_BlockCallDataSize_IsEqualTo_MaxBlockCallDataSize() { - var mockTransaction = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); - var mockTransaction2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); - verifyTransactionSelection(transactionSelector, mockTransaction, SELECTED); - verifyTransactionSelection(transactionSelector, mockTransaction2, SELECTED); + final var evaluationContext1 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext1, SELECTED); + + final var evaluationContext2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext2, SELECTED); } @Test public void shouldNotSelectTransactionWhen_BlockCallDataSize_IsGreaterThan_MaxBlockCallDataSize() { - var mockTransaction = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); - var mockTransaction2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE + 1); - verifyTransactionSelection(transactionSelector, mockTransaction, SELECTED); - verifyTransactionSelection(transactionSelector, mockTransaction2, BLOCK_CALLDATA_OVERFLOW); + final var evaluationContext1 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext1, SELECTED); + + final var evaluationContext2 = mockTransactionOfCallDataSize(BLOCK_CALL_DATA_HALF_SIZE + 1); + verifyTransactionSelection(transactionSelector, evaluationContext2, BLOCK_CALLDATA_OVERFLOW); } @Test public void shouldNotSelectAdditionalTransactionOnceBlockIsFull() { - var firstTransaction = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); - var secondTransaction = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); - var thirdTransaction = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); + final var evaluationContext1 = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext1, SELECTED); + + final var evaluationContext2 = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext2, BLOCK_CALLDATA_OVERFLOW); - verifyTransactionSelection(transactionSelector, firstTransaction, SELECTED); - verifyTransactionSelection(transactionSelector, secondTransaction, BLOCK_CALLDATA_OVERFLOW); - verifyTransactionSelection(transactionSelector, thirdTransaction, BLOCK_CALLDATA_OVERFLOW); + final var evaluationContext3 = mockTransactionOfCallDataSize(TX_CALL_DATA_SIZE); + verifyTransactionSelection(transactionSelector, evaluationContext3, BLOCK_CALLDATA_OVERFLOW); } private void verifyTransactionSelection( final PluginTransactionSelector selector, final TestTransactionEvaluationContext evaluationContext, - final TransactionSelectionResult expectedSelectionResult) { - var selectionResult = selector.evaluateTransactionPreProcessing(evaluationContext); - assertThat(selectionResult).isEqualTo(expectedSelectionResult); - notifySelector(selector, evaluationContext, selectionResult); + final TransactionSelectionResult expectedPreProcessedResult) { + final var preProcessedResult = selector.evaluateTransactionPreProcessing(evaluationContext); + assertThat(preProcessedResult).isEqualTo(expectedPreProcessedResult); + final var processingResult = mock(TransactionProcessingResult.class); + selector.evaluateTransactionPostProcessing(evaluationContext, processingResult); + notifySelector(selector, evaluationContext, preProcessedResult, processingResult); } private void notifySelector( final PluginTransactionSelector selector, final TestTransactionEvaluationContext evaluationContext, - final TransactionSelectionResult selectionResult) { + final TransactionSelectionResult selectionResult, + final TransactionProcessingResult processingResult) { if (selectionResult.equals(SELECTED)) { - selector.onTransactionSelected(evaluationContext, mock(TransactionProcessingResult.class)); + selector.onTransactionSelected(evaluationContext, processingResult); } else { selector.onTransactionNotSelected(evaluationContext, selectionResult); } @@ -102,6 +117,7 @@ private TestTransactionEvaluationContext mockTransactionOfCallDataSize(final int Transaction transaction = mock(Transaction.class); when(pendingTransaction.getTransaction()).thenReturn(transaction); when(transaction.getPayload()).thenReturn(Bytes.repeat((byte) 1, size)); + when(transaction.getHash()).thenReturn(Hash.wrap(Bytes32.repeat((byte) seq++))); return new TestTransactionEvaluationContext( mock(ProcessableBlockHeader.class), pendingTransaction); } diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelectorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelectorTest.java index 289e78781..ae1503e6e 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelectorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/MaxBlockGasTransactionSelectorTest.java @@ -21,12 +21,15 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.apache.tuweni.bytes.Bytes32; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.PendingTransaction; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,58 +37,73 @@ public class MaxBlockGasTransactionSelectorTest { private static final int MAX_GAS_PER_BLOCK = 1000; private static final int MAX_GAS_PER_BLOCK_20_PERCENTAGE = 200; private static final int MAX_GAS_PER_BLOCK_80_PERCENTAGE = 800; - + private static int seq = 1; private PluginTransactionSelector transactionSelector; + private SelectorsStateManager selectorsStateManager; @BeforeEach public void initialize() { - transactionSelector = new MaxBlockGasTransactionSelector(MAX_GAS_PER_BLOCK); + selectorsStateManager = new SelectorsStateManager(); + transactionSelector = + new MaxBlockGasTransactionSelector(selectorsStateManager, MAX_GAS_PER_BLOCK); + selectorsStateManager.blockSelectionStarted(); } @Test public void shouldSelectWhen_GasUsedByTransaction_IsLessThan_MaxGasPerBlock() { - var mockTransactionProcessingResult = mockTransactionProcessingResult(MAX_GAS_PER_BLOCK - 1); + final var mockTransactionProcessingResult = + mockTransactionProcessingResult(MAX_GAS_PER_BLOCK - 1); + final var evaluationContext = mockEvaluationContext(); verifyTransactionSelection( - transactionSelector, mockEvaluationContext(), mockTransactionProcessingResult, SELECTED); + transactionSelector, evaluationContext, mockTransactionProcessingResult, SELECTED); } @Test public void shouldSelectWhen_GasUsedByTransaction_IsEqual_MaxGasPerBlock() { - var mockTransactionProcessingResult = mockTransactionProcessingResult(MAX_GAS_PER_BLOCK); + final var mockTransactionProcessingResult = mockTransactionProcessingResult(MAX_GAS_PER_BLOCK); + final var evaluationContext = mockEvaluationContext(); verifyTransactionSelection( - transactionSelector, mockEvaluationContext(), mockTransactionProcessingResult, SELECTED); + transactionSelector, evaluationContext, mockTransactionProcessingResult, SELECTED); } @Test public void shouldNotSelectWhen_GasUsedByTransaction_IsGreaterThan_MaxGasPerBlock() { - var mockTransactionProcessingResult = mockTransactionProcessingResult(MAX_GAS_PER_BLOCK + 1); + final var mockTransactionProcessingResult = + mockTransactionProcessingResult(MAX_GAS_PER_BLOCK + 1); + final var evaluationContext = mockEvaluationContext(); verifyTransactionSelection( transactionSelector, - mockEvaluationContext(), + evaluationContext, mockTransactionProcessingResult, TX_GAS_EXCEEDS_USER_MAX_BLOCK_GAS); } @Test public void shouldNotSelectWhen_CumulativeGasUsed_IsGreaterThan_MaxGasPerBlock() { + final var evaluationContext1 = mockEvaluationContext(); + // block empty, transaction 80% max gas, should select verifyTransactionSelection( transactionSelector, - mockEvaluationContext(), + evaluationContext1, mockTransactionProcessingResult(MAX_GAS_PER_BLOCK_80_PERCENTAGE), SELECTED); + final var evaluationContext2 = mockEvaluationContext(); + // block 80% full, transaction 80% max gas, should not select verifyTransactionSelection( transactionSelector, - mockEvaluationContext(), + evaluationContext2, mockTransactionProcessingResult(MAX_GAS_PER_BLOCK_80_PERCENTAGE), TX_TOO_LARGE_FOR_REMAINING_USER_GAS); + final var evaluationContext3 = mockEvaluationContext(); + // block 80% full, transaction 20% max gas, should select verifyTransactionSelection( transactionSelector, - mockEvaluationContext(), + evaluationContext3, mockTransactionProcessingResult(MAX_GAS_PER_BLOCK_20_PERCENTAGE), SELECTED); } @@ -105,6 +123,7 @@ private TestTransactionEvaluationContext mockEvaluationContext() { PendingTransaction pendingTransaction = mock(PendingTransaction.class); Transaction transaction = mock(Transaction.class); when(pendingTransaction.getTransaction()).thenReturn(transaction); + when(transaction.getHash()).thenReturn(Hash.wrap(Bytes32.repeat((byte) seq++))); return new TestTransactionEvaluationContext( mock(ProcessableBlockHeader.class), pendingTransaction); } diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TestTransactionEvaluationContext.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TestTransactionEvaluationContext.java index 457822440..d3d978a3e 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TestTransactionEvaluationContext.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TestTransactionEvaluationContext.java @@ -20,8 +20,7 @@ import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; -public class TestTransactionEvaluationContext - implements TransactionEvaluationContext { +public class TestTransactionEvaluationContext implements TransactionEvaluationContext { private ProcessableBlockHeader processableBlockHeader; private PendingTransaction pendingTransaction; private Wei transactionGasPrice; @@ -73,15 +72,4 @@ public TestTransactionEvaluationContext setMinGasPrice(final Wei minGasPrice) { this.minGasPrice = minGasPrice; return this; } - - public TestTransactionEvaluationContext setPendingTransaction( - final PendingTransaction pendingTransaction) { - this.pendingTransaction = pendingTransaction; - return this; - } - - public TestTransactionEvaluationContext setTransactionGasPrice(final Wei transactionGasPrice) { - this.transactionGasPrice = transactionGasPrice; - return this; - } } diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelectorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelectorTest.java index 37ae28a66..6258aed6b 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelectorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txselection/selectors/TraceLineLimitTransactionSelectorTest.java @@ -43,6 +43,7 @@ import org.hyperledger.besu.plugin.data.TransactionProcessingResult; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.plugin.services.txselection.PluginTransactionSelector; +import org.hyperledger.besu.plugin.services.txselection.SelectorsStateManager; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,6 +54,7 @@ public class TraceLineLimitTransactionSelectorTest { private static final String MODULE_LINE_LIMITS_RESOURCE_NAME = "/sequencer/line-limits.toml"; private Map lineCountLimits; private LineaTracerConfiguration lineaTracerConfiguration; + private SelectorsStateManager selectorsStateManager; @TempDir static Path tempDir; static Path lineLimitsConfPath; @@ -78,8 +80,15 @@ public void initialize() { private TestableTraceLineLimitTransactionSelector newSelectorForNewBlock( final Map lineCountLimits) { - return new TestableTraceLineLimitTransactionSelector( - lineaTracerConfiguration, lineCountLimits, OVER_LINE_COUNT_LIMIT_CACHE_SIZE); + selectorsStateManager = new SelectorsStateManager(); + final var selector = + new TestableTraceLineLimitTransactionSelector( + selectorsStateManager, + lineaTracerConfiguration, + lineCountLimits, + OVER_LINE_COUNT_LIMIT_CACHE_SIZE); + selectorsStateManager.blockSelectionStarted(); + return selector; } @Test @@ -88,7 +97,7 @@ public void shouldSelectWhenBelowLimits() { transactionSelector.resetCache(); final var evaluationContext = - mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000); + mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000, 0); verifyTransactionSelection( transactionSelector, evaluationContext, @@ -108,7 +117,7 @@ public void shouldNotSelectWhenOverLimits() { transactionSelector.resetCache(); final var evaluationContext = - mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000); + mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000, 0); verifyTransactionSelection( transactionSelector, evaluationContext, @@ -128,7 +137,7 @@ public void shouldNotReprocessedWhenOverLimits() { transactionSelector.resetCache(); var evaluationContext = - mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000); + mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000, 0); verifyTransactionSelection( transactionSelector, evaluationContext, @@ -168,7 +177,7 @@ public void shouldEvictWhenCacheIsFull() { new TestTransactionEvaluationContext[OVER_LINE_COUNT_LIMIT_CACHE_SIZE + 1]; for (int i = 0; i <= OVER_LINE_COUNT_LIMIT_CACHE_SIZE; i++) { var evaluationContext = - mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000); + mockEvaluationContext(false, 100, Wei.of(1_100_000_000), Wei.of(1_000_000_000), 21000, 0); verifyTransactionSelection( transactionSelector, evaluationContext, @@ -182,7 +191,7 @@ public void shouldEvictWhenCacheIsFull() { .isTrue(); } - // only the last two txs must be in the unprofitable cache, since the first one was evicted + // only the last two txs must be in the over limit cache, since the first one was evicted assertThat( transactionSelector.isOverLineCountLimitTxCached( evaluationContexts[0].getPendingTransaction().getTransaction().getHash())) @@ -232,12 +241,14 @@ private TestTransactionEvaluationContext mockEvaluationContext( final int size, final Wei effectiveGasPrice, final Wei minGasPrice, - final long gasLimit) { + final long gasLimit, + final int payloadSize) { PendingTransaction pendingTransaction = mock(PendingTransaction.class); Transaction transaction = mock(Transaction.class); when(transaction.getHash()).thenReturn(Hash.wrap(Bytes32.random())); when(transaction.getSize()).thenReturn(size); when(transaction.getGasLimit()).thenReturn(gasLimit); + when(transaction.getPayload()).thenReturn(Bytes.repeat((byte) 1, payloadSize)); when(pendingTransaction.getTransaction()).thenReturn(transaction); when(pendingTransaction.hasPriority()).thenReturn(hasPriority); return new TestTransactionEvaluationContext( @@ -247,10 +258,12 @@ private TestTransactionEvaluationContext mockEvaluationContext( private class TestableTraceLineLimitTransactionSelector extends TraceLineLimitTransactionSelector { TestableTraceLineLimitTransactionSelector( + final SelectorsStateManager selectorsStateManager, final LineaTracerConfiguration lineaTracerConfiguration, final Map moduleLimits, final int overLimitCacheSize) { super( + selectorsStateManager, BigInteger.ONE, moduleLimits, LineaTransactionSelectorConfiguration.builder()