From ead1720b52ca5940791a41febe2346af30d0ddf5 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 1 Oct 2024 16:47:48 +0200 Subject: [PATCH 1/6] Set besuVersion=24.9-delivery33 and arithmetizationVersion=0.7.0-rc1 (#89) Signed-off-by: Fabio Di Fabio --- .../plugin/acc/test/TestCommandLineOptionsBuilder.java | 5 +++++ .../besu/tests/acceptance/dsl/AcceptanceTestBase.java | 6 ------ gradle.properties | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java index aae02eab..87248686 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java @@ -40,8 +40,13 @@ public TestCommandLineOptionsBuilder() { cliOptions.setProperty( "--plugin-linea-l1l2-bridge-contract=", "0x00000000000000000000000000000000DEADBEEF"); cliOptions.setProperty("--plugin-linea-l1l2-bridge-topic=", "0x123456"); + // temporarily specify tracer mandatory options, until we improve the ATs to accept a list of + // enabled plugins cliOptions.setProperty("--plugin-linea-conflated-trace-generation-traces-output-path=", "."); cliOptions.setProperty("--plugin-linea-rpc-concurrent-requests-limit=", "1"); + cliOptions.setProperty("--plugin-linea-tracer-readiness-server-port=", "1234"); + cliOptions.setProperty("--plugin-linea-tracer-readiness-server-host=", "localhost"); + cliOptions.setProperty("--plugin-linea-tracer-readiness-max-blocks-behind=", "1"); } public TestCommandLineOptionsBuilder set(String option, String value) { diff --git a/acceptance-tests/src/test/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBase.java b/acceptance-tests/src/test/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBase.java index cec5acbd..f611cbfe 100644 --- a/acceptance-tests/src/test/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBase.java +++ b/acceptance-tests/src/test/java/org/hyperledger/besu/tests/acceptance/dsl/AcceptanceTestBase.java @@ -36,7 +36,6 @@ import org.hyperledger.besu.tests.acceptance.dsl.condition.login.LoginConditions; import org.hyperledger.besu.tests.acceptance.dsl.condition.net.NetConditions; import org.hyperledger.besu.tests.acceptance.dsl.condition.perm.PermissioningConditions; -import org.hyperledger.besu.tests.acceptance.dsl.condition.priv.PrivConditions; import org.hyperledger.besu.tests.acceptance.dsl.condition.process.ExitedWithCode; import org.hyperledger.besu.tests.acceptance.dsl.condition.txpool.TxPoolConditions; import org.hyperledger.besu.tests.acceptance.dsl.condition.web3.Web3Conditions; @@ -54,7 +53,6 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.miner.MinerTransactions; import org.hyperledger.besu.tests.acceptance.dsl.transaction.net.NetTransactions; import org.hyperledger.besu.tests.acceptance.dsl.transaction.perm.PermissioningTransactions; -import org.hyperledger.besu.tests.acceptance.dsl.transaction.privacy.PrivacyTransactions; import org.hyperledger.besu.tests.acceptance.dsl.transaction.txpool.TxPoolTransactions; import org.hyperledger.besu.tests.acceptance.dsl.transaction.web3.Web3Transactions; import org.junit.jupiter.api.AfterEach; @@ -88,8 +86,6 @@ public class AcceptanceTestBase { protected final PermissioningTransactions permissioningTransactions; protected final MinerTransactions minerTransactions; protected final Web3Conditions web3; - protected final PrivConditions priv; - protected final PrivacyTransactions privacyTransactions; protected final TxPoolConditions txPoolConditions; protected final TxPoolTransactions txPoolTransactions; protected final ExitedWithCode exitedSuccessfully; @@ -104,7 +100,6 @@ protected AcceptanceTestBase() { bftTransactions = new BftTransactions(); accountTransactions = new AccountTransactions(accounts); permissioningTransactions = new PermissioningTransactions(); - privacyTransactions = new PrivacyTransactions(); contractTransactions = new ContractTransactions(); minerTransactions = new MinerTransactions(); @@ -116,7 +111,6 @@ protected AcceptanceTestBase() { net = new NetConditions(new NetTransactions()); cluster = new Cluster(net); perm = new PermissioningConditions(permissioningTransactions); - priv = new PrivConditions(privacyTransactions); admin = new AdminConditions(adminTransactions); web3 = new Web3Conditions(new Web3Transactions()); besu = new BesuNodeFactory(); diff --git a/gradle.properties b/gradle.properties index 3e03ac01..30db94f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ -releaseVersion=0.6.0-rc8.1 -besuVersion=24.9-delivery32 -arithmetizationVersion=0.6.0-rc8 +releaseVersion=0.7.0-rc1.1 +besuVersion=24.9-delivery33 +arithmetizationVersion=0.7.0-rc1 besuArtifactGroup=io.consensys.linea-besu distributionIdentifier=linea-sequencer distributionBaseUrl=https://artifacts.consensys.net/public/linea-besu/raw/names/linea-besu.tar.gz/versions/ \ No newline at end of file From 624b99de0ead0a3bed826a3badaff71da609550e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 2 Oct 2024 17:10:54 +0200 Subject: [PATCH 2/6] Set besuVersion=24.10-delivery34 and arithmetizationVersion=0.8.0-rc1 (#90) Signed-off-by: Fabio Di Fabio --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 30db94f5..f0e3c8c0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ -releaseVersion=0.7.0-rc1.1 -besuVersion=24.9-delivery33 -arithmetizationVersion=0.7.0-rc1 +releaseVersion=0.8.0-rc1.1 +besuVersion=24.10-delivery34 +arithmetizationVersion=0.8.0-rc1 besuArtifactGroup=io.consensys.linea-besu distributionIdentifier=linea-sequencer distributionBaseUrl=https://artifacts.consensys.net/public/linea-besu/raw/names/linea-besu.tar.gz/versions/ \ No newline at end of file From fcd99a4c78583df13f0bc5846263410e29023b45 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 3 Oct 2024 06:30:09 +0200 Subject: [PATCH 3/6] Use required plugins in ATs to not register tracer plugins (#91) Signed-off-by: Fabio Di Fabio --- .../java/linea/plugin/acc/test/BlockGasLimitTest.java | 3 +-- .../java/linea/plugin/acc/test/LineaPluginTestBase.java | 9 ++++++++- .../plugin/acc/test/TestCommandLineOptionsBuilder.java | 7 ------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/BlockGasLimitTest.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/BlockGasLimitTest.java index b2057972..b1decd2c 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/BlockGasLimitTest.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/BlockGasLimitTest.java @@ -41,8 +41,7 @@ public List getTestCliOptions() { @Override @BeforeEach public void setup() throws Exception { - minerNode = besu.createMinerNodeWithExtraCliOptions("miner1", getTestCliOptions()); - cluster.start(minerNode); + super.setup(); minerNode.execute(minerTransactions.minerStop()); } 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 036154ef..c5d08d7a 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 @@ -121,7 +121,14 @@ private BesuNode createCliqueNodeWithExtraCliOptionsAndRpcApis( .jsonRpcTxPool() .genesisConfigProvider( validators -> Optional.of(provideGenesisConfig(validators, cliqueOptions))) - .extraCLIOptions(extraCliOptions); + .extraCLIOptions(extraCliOptions) + .requestedPlugins( + List.of( + "LineaExtraDataPlugin", + "LineaEstimateGasEndpointPlugin", + "LineaSetExtraDataEndpointPlugin", + "LineaTransactionPoolValidatorPlugin", + "LineaTransactionSelectorPlugin")); return besu.create(nodeConfBuilder.build()); } diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java index 87248686..138ca23e 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/TestCommandLineOptionsBuilder.java @@ -40,13 +40,6 @@ public TestCommandLineOptionsBuilder() { cliOptions.setProperty( "--plugin-linea-l1l2-bridge-contract=", "0x00000000000000000000000000000000DEADBEEF"); cliOptions.setProperty("--plugin-linea-l1l2-bridge-topic=", "0x123456"); - // temporarily specify tracer mandatory options, until we improve the ATs to accept a list of - // enabled plugins - cliOptions.setProperty("--plugin-linea-conflated-trace-generation-traces-output-path=", "."); - cliOptions.setProperty("--plugin-linea-rpc-concurrent-requests-limit=", "1"); - cliOptions.setProperty("--plugin-linea-tracer-readiness-server-port=", "1234"); - cliOptions.setProperty("--plugin-linea-tracer-readiness-server-host=", "localhost"); - cliOptions.setProperty("--plugin-linea-tracer-readiness-max-blocks-behind=", "1"); } public TestCommandLineOptionsBuilder set(String option, String value) { From 8e9fe21a5f469b5927671746b69b1226b772c0be Mon Sep 17 00:00:00 2001 From: Usman Saleem Date: Fri, 4 Oct 2024 09:21:15 +1000 Subject: [PATCH 4/6] feat: Report rejected transactions to an external service for tx pool validators used by LineaTransactionPoolValidatorPlugin (#85) * Extract reporting endpoint URI cli option * Linea Transaction Pool Validator to report rejected tx * Linea node type and refactored request builder * Update unit tests to use refactored generateSaveRejectedTxJsonRpc * Use transactionSelectionResult.toString in LineaTransactionSelector * Use Mutually exclusive = false for co-dep cli options * Add unit test for cli options. Change endpoint type to URL * JsonRpcManager - Use plugin identifier to create sub directories to store rpc calls * JsonRpcManager convert submitNewJsonRpcCall to do async chaining before calling submitJsonRpcCall * Add rej tx reporting to all tx pool validators --- CHANGELOG.md | 3 +- gradle/dependency-management.gradle | 1 + sequencer/build.gradle | 2 +- .../AbstractLineaPrivateOptionsPlugin.java | 10 ++ .../consensys/linea/config/LineaNodeType.java | 23 +++ .../LineaRejectedTxReportingCliOptions.java | 117 ++++++++++++++++ ...LineaRejectedTxReportingConfiguration.java | 26 ++++ .../LineaTransactionSelectorCliOptions.java | 14 -- ...LineaTransactionSelectorConfiguration.java | 5 +- .../linea/jsonrpc/JsonRpcManager.java | 84 +++++++---- .../linea/jsonrpc/JsonRpcRequestBuilder.java | 99 ++++++++----- .../LineaTransactionPoolValidatorFactory.java | 18 ++- .../LineaTransactionPoolValidatorPlugin.java | 25 +++- .../validators/AllowedAddressValidator.java | 29 +++- .../validators/CalldataValidator.java | 21 +++ .../validators/GasLimitValidator.java | 21 +++ .../validators/ProfitabilityValidator.java | 47 +++++-- .../validators/SimulationValidator.java | 30 +++- .../LineaTransactionSelectorPlugin.java | 13 +- .../selectors/LineaTransactionSelector.java | 11 +- ...ineaRejectedTxReportingCliOptionsTest.java | 131 ++++++++++++++++++ .../jsonrpc/JsonRpcManagerStartTest.java | 38 +++-- .../linea/jsonrpc/JsonRpcManagerTest.java | 85 +++++++----- .../AllowedAddressValidatorTest.java | 2 +- .../validators/CalldataValidatorTest.java | 3 +- .../validators/GasLimitValidatorTest.java | 3 +- .../ProfitabilityValidatorTest.java | 12 +- .../validators/SimulationValidatorTest.java | 74 +++++++++- 28 files changed, 773 insertions(+), 174 deletions(-) create mode 100644 sequencer/src/main/java/net/consensys/linea/config/LineaNodeType.java create mode 100644 sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java create mode 100644 sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingConfiguration.java create mode 100644 sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fd54d66..786ddd1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog ## Next release -* feat: Report rejected transactions to an external service [#69](https://github.com/Consensys/linea-sequencer/pull/69) +* feat: Report rejected transactions to an external service for validators used by LineaTransactionPoolValidatorPlugin [#85](https://github.com/Consensys/linea-sequencer/pull/85) +* feat: Report rejected transactions to an external service for LineaTransactionSelector used by LineaTransactionSelectorPlugin [#69](https://github.com/Consensys/linea-sequencer/pull/69) ## 0.6.0-rc1.1 * bump linea-arithmetization version to 0.6.0-rc1 [#71](https://github.com/Consensys/linea-sequencer/pull/71) diff --git a/gradle/dependency-management.gradle b/gradle/dependency-management.gradle index 8453dfdc..2b4d17c7 100644 --- a/gradle/dependency-management.gradle +++ b/gradle/dependency-management.gradle @@ -78,6 +78,7 @@ dependencyManagement { entry "dsl" entry "eth" entry "rlp" + entry "besu" } dependencySet(group: 'ch.qos.logback', version: '1.5.6') { diff --git a/sequencer/build.gradle b/sequencer/build.gradle index a68b8970..dea8ed49 100644 --- a/sequencer/build.gradle +++ b/sequencer/build.gradle @@ -69,8 +69,8 @@ dependencies { testImplementation "${besuArtifactGroup}:besu-datatypes" testImplementation "${besuArtifactGroup}.internal:core" testImplementation "${besuArtifactGroup}.internal:rlp" - testImplementation "${besuArtifactGroup}.internal:core" testImplementation "${besuArtifactGroup}:plugin-api" + testImplementation "${besuArtifactGroup}.internal:besu" testImplementation "org.awaitility:awaitility" // workaround for bug https://github.com/dnsjava/dnsjava/issues/329, remove when upgraded upstream diff --git a/sequencer/src/main/java/net/consensys/linea/AbstractLineaPrivateOptionsPlugin.java b/sequencer/src/main/java/net/consensys/linea/AbstractLineaPrivateOptionsPlugin.java index 8a7bf553..569e6281 100644 --- a/sequencer/src/main/java/net/consensys/linea/AbstractLineaPrivateOptionsPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/AbstractLineaPrivateOptionsPlugin.java @@ -22,6 +22,8 @@ import net.consensys.linea.compress.LibCompress; import net.consensys.linea.config.LineaProfitabilityCliOptions; import net.consensys.linea.config.LineaProfitabilityConfiguration; +import net.consensys.linea.config.LineaRejectedTxReportingCliOptions; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import net.consensys.linea.config.LineaRpcCliOptions; import net.consensys.linea.config.LineaRpcConfiguration; import net.consensys.linea.config.LineaTracerCliOptions; @@ -68,6 +70,9 @@ public Map getLineaPluginConfigMap() { configMap.put( LineaTracerCliOptions.CONFIG_KEY, LineaTracerCliOptions.create().asPluginConfig()); + configMap.put( + LineaRejectedTxReportingCliOptions.CONFIG_KEY, + LineaRejectedTxReportingCliOptions.create().asPluginConfig()); return configMap; } @@ -96,6 +101,11 @@ public LineaTracerConfiguration tracerConfiguration() { getConfigurationByKey(LineaTracerCliOptions.CONFIG_KEY).optionsConfig(); } + public LineaRejectedTxReportingConfiguration rejectedTxReportingConfiguration() { + return (LineaRejectedTxReportingConfiguration) + getConfigurationByKey(LineaRejectedTxReportingCliOptions.CONFIG_KEY).optionsConfig(); + } + @Override public void start() { super.start(); diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaNodeType.java b/sequencer/src/main/java/net/consensys/linea/config/LineaNodeType.java new file mode 100644 index 00000000..5bdb40fe --- /dev/null +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaNodeType.java @@ -0,0 +1,23 @@ +/* + * 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.config; + +/** Linea node type that is used when reporting rejected transactions. */ +public enum LineaNodeType { + SEQUENCER, + RPC, + P2P +} diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java new file mode 100644 index 00000000..53b84762 --- /dev/null +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java @@ -0,0 +1,117 @@ +/* + * 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.config; + +import java.net.URL; +import java.util.Optional; + +import com.google.common.base.MoreObjects; +import net.consensys.linea.plugins.LineaCliOptions; +import picocli.CommandLine.ArgGroup; +import picocli.CommandLine.Option; + +/** The Linea Rejected Transaction Reporting CLI options. */ +public class LineaRejectedTxReportingCliOptions implements LineaCliOptions { + /** + * The configuration key used in AbstractLineaPrivateOptionsPlugin to identify the cli options. + */ + public static final String CONFIG_KEY = "rejected-tx-reporting-config"; + + /** The rejected transaction endpoint. */ + public static final String REJECTED_TX_ENDPOINT = "--plugin-linea-rejected-tx-endpoint"; + + /** The Linea node type. */ + public static final String LINEA_NODE_TYPE = "--plugin-linea-node-type"; + + @ArgGroup(exclusive = false) + DependentOptions dependentOptions; // will be null if no options from this group are specified + + static class DependentOptions { + @Option( + names = {REJECTED_TX_ENDPOINT}, + hidden = true, + required = true, // required within the group + paramLabel = "", + description = + "Endpoint URI for reporting rejected transactions. Specify a valid URI to enable reporting.") + URL rejectedTxEndpoint = null; + + @Option( + names = {LINEA_NODE_TYPE}, + hidden = true, + required = true, // required within the group + paramLabel = "", + description = + "Linea Node type to use when reporting rejected transactions. (default: ${DEFAULT-VALUE}. Valid values: ${COMPLETION-CANDIDATES})") + LineaNodeType lineaNodeType = null; + } + + /** Default constructor. */ + private LineaRejectedTxReportingCliOptions() {} + + /** + * Create Linea Rejected Transaction Reporting CLI options. + * + * @return the Linea Rejected Transaction Reporting CLI options + */ + public static LineaRejectedTxReportingCliOptions create() { + return new LineaRejectedTxReportingCliOptions(); + } + + /** + * Instantiates a new Linea rejected tx reporting cli options from Configuration object + * + * @param config An instance of LineaRejectedTxReportingConfiguration + */ + public static LineaRejectedTxReportingCliOptions fromConfig( + final LineaRejectedTxReportingConfiguration config) { + final LineaRejectedTxReportingCliOptions options = create(); + // both options are required. + if (config.rejectedTxEndpoint() != null && config.lineaNodeType() != null) { + final var depOpts = new DependentOptions(); + depOpts.rejectedTxEndpoint = config.rejectedTxEndpoint(); + depOpts.lineaNodeType = config.lineaNodeType(); + options.dependentOptions = depOpts; + } + + return options; + } + + @Override + public LineaRejectedTxReportingConfiguration toDomainObject() { + final var rejectedTxEndpoint = + Optional.ofNullable(dependentOptions).map(o -> o.rejectedTxEndpoint).orElse(null); + final var lineaNodeType = + Optional.ofNullable(dependentOptions).map(o -> o.lineaNodeType).orElse(null); + + return LineaRejectedTxReportingConfiguration.builder() + .rejectedTxEndpoint(rejectedTxEndpoint) + .lineaNodeType(lineaNodeType) + .build(); + } + + @Override + public String toString() { + final var rejectedTxEndpoint = + Optional.ofNullable(dependentOptions).map(o -> o.rejectedTxEndpoint).orElse(null); + final var lineaNodeType = + Optional.ofNullable(dependentOptions).map(o -> o.lineaNodeType).orElse(null); + + return MoreObjects.toStringHelper(this) + .add(REJECTED_TX_ENDPOINT, rejectedTxEndpoint) + .add(LINEA_NODE_TYPE, lineaNodeType) + .toString(); + } +} diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingConfiguration.java b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingConfiguration.java new file mode 100644 index 00000000..607d0410 --- /dev/null +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingConfiguration.java @@ -0,0 +1,26 @@ +/* + * 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.config; + +import java.net.URL; + +import lombok.Builder; +import net.consensys.linea.plugins.LineaOptionsConfiguration; + +/** Linea Rejected Transactions Reporting Configuration */ +@Builder(toBuilder = true) +public record LineaRejectedTxReportingConfiguration( + URL rejectedTxEndpoint, LineaNodeType lineaNodeType) implements LineaOptionsConfiguration {} diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorCliOptions.java b/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorCliOptions.java index 3eadcaa3..e5b20e30 100644 --- a/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorCliOptions.java +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorCliOptions.java @@ -15,8 +15,6 @@ package net.consensys.linea.config; -import java.net.URI; - import com.google.common.base.MoreObjects; import jakarta.validation.constraints.Positive; import net.consensys.linea.plugins.LineaCliOptions; @@ -41,8 +39,6 @@ public class LineaTransactionSelectorCliOptions implements LineaCliOptions { public static final String UNPROFITABLE_RETRY_LIMIT = "--plugin-linea-unprofitable-retry-limit"; public static final int DEFAULT_UNPROFITABLE_RETRY_LIMIT = 10; - public static final String REJECTED_TX_ENDPOINT = "--plugin-linea-rejected-tx-endpoint"; - @Positive @CommandLine.Option( names = {MAX_BLOCK_CALLDATA_SIZE}, @@ -86,13 +82,6 @@ public class LineaTransactionSelectorCliOptions implements LineaCliOptions { "Max number of unprofitable transactions we retry on each block creation (default: ${DEFAULT-VALUE})") private int unprofitableRetryLimit = DEFAULT_UNPROFITABLE_RETRY_LIMIT; - @CommandLine.Option( - names = {REJECTED_TX_ENDPOINT}, - hidden = true, - paramLabel = "", - description = "Endpoint URI for reporting rejected transactions (default: ${DEFAULT-VALUE})") - private URI rejectedTxEndpoint = null; - private LineaTransactionSelectorCliOptions() {} /** @@ -118,7 +107,6 @@ public static LineaTransactionSelectorCliOptions fromConfig( options.maxGasPerBlock = config.maxGasPerBlock(); options.unprofitableCacheSize = config.unprofitableCacheSize(); options.unprofitableRetryLimit = config.unprofitableRetryLimit(); - options.rejectedTxEndpoint = config.rejectedTxEndpoint(); return options; } @@ -135,7 +123,6 @@ public LineaTransactionSelectorConfiguration toDomainObject() { .maxGasPerBlock(maxGasPerBlock) .unprofitableCacheSize(unprofitableCacheSize) .unprofitableRetryLimit(unprofitableRetryLimit) - .rejectedTxEndpoint(rejectedTxEndpoint) .build(); } @@ -147,7 +134,6 @@ public String toString() { .add(MAX_GAS_PER_BLOCK, maxGasPerBlock) .add(UNPROFITABLE_CACHE_SIZE, unprofitableCacheSize) .add(UNPROFITABLE_RETRY_LIMIT, unprofitableRetryLimit) - .add(REJECTED_TX_ENDPOINT, rejectedTxEndpoint) .toString(); } } diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorConfiguration.java b/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorConfiguration.java index 726c8932..6c178797 100644 --- a/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorConfiguration.java +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaTransactionSelectorConfiguration.java @@ -15,8 +15,6 @@ package net.consensys.linea.config; -import java.net.URI; - import lombok.Builder; import net.consensys.linea.plugins.LineaOptionsConfiguration; @@ -27,6 +25,5 @@ public record LineaTransactionSelectorConfiguration( int overLinesLimitCacheSize, long maxGasPerBlock, int unprofitableCacheSize, - int unprofitableRetryLimit, - URI rejectedTxEndpoint) + int unprofitableRetryLimit) implements LineaOptionsConfiguration {} diff --git a/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcManager.java b/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcManager.java index c2a5b530..7110bcc9 100644 --- a/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcManager.java +++ b/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcManager.java @@ -17,7 +17,6 @@ import java.io.IOException; import java.io.UncheckedIOException; -import java.net.URI; import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; @@ -30,6 +29,8 @@ import java.util.Map; import java.util.TreeSet; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -39,7 +40,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; +import lombok.NonNull; import lombok.extern.slf4j.Slf4j; +import net.consensys.linea.config.LineaNodeType; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -52,26 +56,37 @@ public class JsonRpcManager { private static final Duration INITIAL_RETRY_DELAY_DURATION = Duration.ofSeconds(1); private static final Duration MAX_RETRY_DURATION = Duration.ofHours(2); private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + static final String JSON_RPC_DIR = "rej-tx-rpc"; + static final String DISCARDED_DIR = "discarded"; private final OkHttpClient client = new OkHttpClient(); private final ObjectMapper objectMapper = new ObjectMapper(); private final Map fileStartTimes = new ConcurrentHashMap<>(); - private final Path rejTxRpcDirectory; - private final URI rejectedTxEndpoint; + private final Path jsonRpcDir; + private final LineaRejectedTxReportingConfiguration reportingConfiguration; private final ExecutorService executorService; private final ScheduledExecutorService retrySchedulerService; /** * Creates a new JSON-RPC manager. * + * @param pluginIdentifier The plugin identifier will be created as a sub-directory under + * rej-tx-rpc. The rejected transactions will be stored under it for each plugin that uses it. * @param besuDataDir Path to Besu data directory. The json-rpc files will be stored here under * rej-tx-rpc subdirectory. - * @param rejectedTxEndpoint The endpoint to send rejected transactions to + * @param reportingConfiguration Instance of LineaRejectedTxReportingConfiguration containing the + * endpoint URI and node type. */ - public JsonRpcManager(final Path besuDataDir, final URI rejectedTxEndpoint) { - this.rejTxRpcDirectory = besuDataDir.resolve("rej_tx_rpc"); - this.rejectedTxEndpoint = rejectedTxEndpoint; + public JsonRpcManager( + @NonNull final String pluginIdentifier, + @NonNull final Path besuDataDir, + @NonNull final LineaRejectedTxReportingConfiguration reportingConfiguration) { + if (reportingConfiguration.rejectedTxEndpoint() == null) { + throw new IllegalStateException("Rejected transaction endpoint URI is required"); + } + this.jsonRpcDir = besuDataDir.resolve(JSON_RPC_DIR).resolve(pluginIdentifier); + this.reportingConfiguration = reportingConfiguration; this.executorService = Executors.newVirtualThreadPerTaskExecutor(); this.retrySchedulerService = Executors.newSingleThreadScheduledExecutor(); } @@ -79,14 +94,14 @@ public JsonRpcManager(final Path besuDataDir, final URI rejectedTxEndpoint) { /** Load existing JSON-RPC and submit them. */ public JsonRpcManager start() { try { - // Create the rej_tx_rpc/discarded directories if it doesn't exist - Files.createDirectories(rejTxRpcDirectory.resolve("discarded")); + // Create the rej-tx-rpc/pluginIdentifier/discarded directories if it doesn't exist + Files.createDirectories(jsonRpcDir.resolve(DISCARDED_DIR)); // Load existing JSON files processExistingJsonFiles(); return this; } catch (final IOException e) { - log.error("Failed to create or access directory: {}", rejTxRpcDirectory, e); + log.error("Failed to create or access directories under: {}", jsonRpcDir, e); throw new UncheckedIOException(e); } } @@ -102,25 +117,37 @@ public void shutdown() { * * @param jsonContent The JSON content to submit */ - public void submitNewJsonRpcCall(final String jsonContent) { - final Path jsonFile; - try { - jsonFile = saveJsonToDir(jsonContent, rejTxRpcDirectory); - } catch (final IOException e) { - log.error("Failed to save JSON-RPC content", e); - return; - } + public void submitNewJsonRpcCallAsync(final String jsonContent) { + CompletableFuture.supplyAsync( + () -> { + try { + Path jsonFile = saveJsonToDir(jsonContent, jsonRpcDir); + fileStartTimes.put(jsonFile, Instant.now()); + return jsonFile; + } catch (final IOException e) { + log.error("Failed to save JSON-RPC content", e); + throw new CompletionException(e); + } + }, + executorService) + .thenAcceptAsync( + jsonFile -> submitJsonRpcCall(jsonFile, INITIAL_RETRY_DELAY_DURATION), executorService) + .exceptionally( + e -> { + log.error("Error in submitNewJsonRpcCall", e); + return null; + }); + } - fileStartTimes.put(jsonFile, Instant.now()); - submitJsonRpcCall(jsonFile, INITIAL_RETRY_DELAY_DURATION); + public LineaNodeType getNodeType() { + return reportingConfiguration.lineaNodeType(); } private void processExistingJsonFiles() { try { final TreeSet sortedFiles = new TreeSet<>(Comparator.comparing(Path::getFileName)); - try (DirectoryStream stream = - Files.newDirectoryStream(rejTxRpcDirectory, "rpc_*.json")) { + try (DirectoryStream stream = Files.newDirectoryStream(jsonRpcDir, "rpc_*.json")) { for (Path path : stream) { sortedFiles.add(path); } @@ -155,7 +182,7 @@ private void submitJsonRpcCall(final Path jsonFile, final Duration nextDelay) { log.error( "Failed to send JSON-RPC file {} to {}, Scheduling retry ...", jsonFile, - rejectedTxEndpoint); + reportingConfiguration.rejectedTxEndpoint()); scheduleRetry(jsonFile, nextDelay); } } catch (final Exception e) { @@ -189,8 +216,7 @@ private void scheduleRetry(final Path jsonFile, final Duration currentDelay) { TimeUnit.MILLISECONDS); } else { log.error("Exceeded maximum retry duration for JSON-RPC file: {}.", jsonFile); - final Path destination = - rejTxRpcDirectory.resolve("discarded").resolve(jsonFile.getFileName()); + final Path destination = jsonRpcDir.resolve(DISCARDED_DIR).resolve(jsonFile.getFileName()); try { Files.move(jsonFile, destination, StandardCopyOption.REPLACE_EXISTING); @@ -209,7 +235,8 @@ private void scheduleRetry(final Path jsonFile, final Duration currentDelay) { private boolean sendJsonRpcCall(final String jsonContent) { final RequestBody body = RequestBody.create(jsonContent, JSON); final Request request = - new Request.Builder().url(rejectedTxEndpoint.toString()).post(body).build(); + new Request.Builder().url(reportingConfiguration.rejectedTxEndpoint()).post(body).build(); + try (final Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { log.error("Unexpected response code from rejected-tx endpoint: {}", response.code()); @@ -242,7 +269,10 @@ private boolean sendJsonRpcCall(final String jsonContent) { log.warn("Unexpected rejected-tx JSON-RPC response format: {}", responseBody); return false; } catch (final IOException e) { - log.error("Failed to send JSON-RPC call to rejected-tx endpoint {}", rejectedTxEndpoint, e); + log.error( + "Failed to send JSON-RPC call to rejected-tx endpoint {}", + reportingConfiguration.rejectedTxEndpoint(), + e); return false; } } diff --git a/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcRequestBuilder.java b/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcRequestBuilder.java index 26906eea..4bd4dc69 100644 --- a/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcRequestBuilder.java +++ b/sequencer/src/main/java/net/consensys/linea/jsonrpc/JsonRpcRequestBuilder.java @@ -16,57 +16,80 @@ package net.consensys.linea.jsonrpc; import java.time.Instant; +import java.util.List; +import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import org.hyperledger.besu.datatypes.PendingTransaction; -import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; -import org.hyperledger.besu.plugin.data.TransactionSelectionResult; -import org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext; +import net.consensys.linea.config.LineaNodeType; +import net.consensys.linea.sequencer.modulelimit.ModuleLimitsValidationResult; +import org.hyperledger.besu.datatypes.Transaction; -/** Helper class to build JSON-RPC requests for rejected transactions. */ +/** + * Helper class to build JSON-RPC requests for rejected transactions. + * + *
+ * {@code linea_saveRejectedTransactionV1({
+ *         "txRejectionStage": "SEQUENCER/RPC/P2P",
+ *         "timestamp": "2024-08-22T09:18:51Z", # ISO8601 UTC+0 when tx was rejected by node, usefull if P2P edge node.
+ *         "blockNumber": "base 10 number",
+ *         "transactionRLP": "transaction as the user sent in eth_sendRawTransaction",
+ *         "reason": "Transaction line count for module ADD=402 is above the limit 70"
+ *         "overflows": [{
+ *           "module": "ADD",
+ *           "count": 402,
+ *           "limit": 70
+ *         }, {
+ *           "module": "MUL",
+ *           "count": 587,
+ *           "limit": 400
+ *         }]
+ *     })
+ * }
+ * 
+ */ public class JsonRpcRequestBuilder { private static final AtomicLong idCounter = new AtomicLong(1); /** + * Generate linea_saveRejectedTransactionV1 JSON-RPC request from given arguments. * - * - *
-   * {@code linea_saveRejectedTransactionV1({
-   *         "txRejectionStage": "SEQUENCER/RPC/P2P",
-   *         "timestamp": "2024-08-22T09:18:51Z", # ISO8601 UTC+0 when tx was rejected by node, usefull if P2P edge node.
-   *         "blockNumber": "base 10 number",
-   *         "transactionRLP": "transaction as the user sent in eth_sendRawTransaction",
-   *         "reason": "Transaction line count for module ADD=402 is above the limit 70"
-   *         "overflows": [{
-   *           "module": "ADD",
-   *           "count": 402,
-   *           "limit": 70
-   *         }, {
-   *           "module": "MUL",
-   *           "count": 587,
-   *           "limit": 400
-   *         }]
-   *     })
-   * }
-   * 
+ * @param lineaNodeType Linea node type which is reporting the rejected transaction. + * @param transaction The rejected transaction. The encoded transaction RLP is used in the + * JSON-RPC request. + * @param timestamp The timestamp when the transaction was rejected. + * @param blockNumber Optional block number where the transaction was rejected. Used for sequencer + * node. + * @param reasonMessage The reason message for the rejection. + * @return JSON-RPC request as a string. */ - public static String buildRejectedTxRequest( - final TransactionEvaluationContext evaluationContext, - final TransactionSelectionResult transactionSelectionResult, - final Instant timestamp) { - final PendingTransaction pendingTransaction = evaluationContext.getPendingTransaction(); - final ProcessableBlockHeader pendingBlockHeader = evaluationContext.getPendingBlockHeader(); - - // Build JSON-RPC request + public static String generateSaveRejectedTxJsonRpc( + final LineaNodeType lineaNodeType, + final Transaction transaction, + final Instant timestamp, + final Optional blockNumber, + final String reasonMessage, + final List overflowValidationResults) { final JsonObject params = new JsonObject(); - params.addProperty("txRejectionStage", "SEQUENCER"); + params.addProperty("txRejectionStage", lineaNodeType.name()); params.addProperty("timestamp", timestamp.toString()); - params.addProperty("blockNumber", pendingBlockHeader.getNumber()); - params.addProperty( - "transactionRLP", pendingTransaction.getTransaction().encoded().toHexString()); - params.addProperty("reasonMessage", transactionSelectionResult.maybeInvalidReason().orElse("")); + blockNumber.ifPresent(number -> params.addProperty("blockNumber", number)); + params.addProperty("transactionRLP", transaction.encoded().toHexString()); + params.addProperty("reasonMessage", reasonMessage); + + // overflows + final JsonArray overflows = new JsonArray(); + for (ModuleLimitsValidationResult result : overflowValidationResults) { + JsonObject overflow = new JsonObject(); + overflow.addProperty("module", result.getModuleName()); + overflow.addProperty("count", result.getModuleLineCount()); + overflow.addProperty("limit", result.getModuleLineLimit()); + overflows.add(overflow); + } + params.add("overflows", overflows); + // request final JsonObject request = new JsonObject(); request.addProperty("jsonrpc", "2.0"); request.addProperty("method", "linea_saveRejectedTransactionV1"); diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorFactory.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorFactory.java index c637097a..dc5759f1 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorFactory.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/LineaTransactionPoolValidatorFactory.java @@ -22,6 +22,7 @@ import net.consensys.linea.config.LineaProfitabilityConfiguration; import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration; import net.consensys.linea.sequencer.txpoolvalidation.validators.AllowedAddressValidator; import net.consensys.linea.sequencer.txpoolvalidation.validators.CalldataValidator; @@ -46,6 +47,7 @@ public class LineaTransactionPoolValidatorFactory implements PluginTransactionPo private final Set
denied; private final Map moduleLineLimitsMap; private final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration; + private final Optional rejectedTxJsonRpcManager; public LineaTransactionPoolValidatorFactory( final BesuConfiguration besuConfiguration, @@ -55,7 +57,8 @@ public LineaTransactionPoolValidatorFactory( final LineaProfitabilityConfiguration profitabilityConf, final Set
deniedAddresses, final Map moduleLineLimitsMap, - final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration) { + final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, + final Optional rejectedTxJsonRpcManager) { this.besuConfiguration = besuConfiguration; this.blockchainService = blockchainService; this.transactionSimulationService = transactionSimulationService; @@ -64,6 +67,7 @@ public LineaTransactionPoolValidatorFactory( this.denied = deniedAddresses; this.moduleLineLimitsMap = moduleLineLimitsMap; this.l1L2BridgeConfiguration = l1L2BridgeConfiguration; + this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager; } /** @@ -76,16 +80,18 @@ public LineaTransactionPoolValidatorFactory( public PluginTransactionPoolValidator createTransactionValidator() { final var validators = new PluginTransactionPoolValidator[] { - new AllowedAddressValidator(denied), - new GasLimitValidator(txPoolValidatorConf), - new CalldataValidator(txPoolValidatorConf), - new ProfitabilityValidator(besuConfiguration, blockchainService, profitabilityConf), + new AllowedAddressValidator(denied, rejectedTxJsonRpcManager), + new GasLimitValidator(txPoolValidatorConf, rejectedTxJsonRpcManager), + new CalldataValidator(txPoolValidatorConf, rejectedTxJsonRpcManager), + new ProfitabilityValidator( + besuConfiguration, blockchainService, profitabilityConf, rejectedTxJsonRpcManager), new SimulationValidator( blockchainService, transactionSimulationService, txPoolValidatorConf, moduleLineLimitsMap, - l1L2BridgeConfiguration) + l1L2BridgeConfiguration, + rejectedTxJsonRpcManager) }; return (transaction, isLocal, hasPriority) -> 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 a0b28aa3..0db9229f 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 @@ -28,6 +28,8 @@ import com.google.auto.service.AutoService; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.AbstractLineaRequiredPlugin; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; @@ -50,6 +52,7 @@ public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPl private BlockchainService blockchainService; private TransactionPoolValidatorService transactionPoolValidatorService; private TransactionSimulationService transactionSimulationService; + private Optional rejectedTxJsonRpcManager = Optional.empty(); @Override public Optional getName() { @@ -100,6 +103,19 @@ public void start() { final Set
deniedAddresses = lines.map(l -> Address.fromHexString(l.trim())).collect(Collectors.toUnmodifiableSet()); + // start the optional json rpc manager for rejected tx reporting + final LineaRejectedTxReportingConfiguration lineaRejectedTxReportingConfiguration = + rejectedTxReportingConfiguration(); + rejectedTxJsonRpcManager = + Optional.ofNullable(lineaRejectedTxReportingConfiguration.rejectedTxEndpoint()) + .map( + endpoint -> + new JsonRpcManager( + "linea-tx-pool-validator-plugin", + besuConfiguration.getDataPath(), + lineaRejectedTxReportingConfiguration) + .start()); + transactionPoolValidatorService.registerPluginTransactionValidatorFactory( new LineaTransactionPoolValidatorFactory( besuConfiguration, @@ -109,10 +125,17 @@ public void start() { profitabilityConfiguration(), deniedAddresses, createLimitModules(tracerConfiguration()), - l1L2BridgeSharedConfiguration())); + l1L2BridgeSharedConfiguration(), + rejectedTxJsonRpcManager)); } catch (Exception e) { throw new RuntimeException(e); } } + + @Override + public void stop() { + super.stop(); + rejectedTxJsonRpcManager.ifPresent(JsonRpcManager::shutdown); + } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidator.java index 489f9ede..a272ea7f 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidator.java @@ -14,11 +14,15 @@ */ package net.consensys.linea.sequencer.txpoolvalidation.validators; +import java.time.Instant; +import java.util.List; import java.util.Optional; import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import net.consensys.linea.jsonrpc.JsonRpcManager; +import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidator; @@ -44,15 +48,15 @@ public class AllowedAddressValidator implements PluginTransactionPoolValidator { Address.fromHexString("0x000000000000000000000000000000000000000a")); private final Set
denied; + private final Optional rejectedTxJsonRpcManager; @Override public Optional validateTransaction( final Transaction transaction, final boolean isLocal, final boolean hasPriority) { - final var maybeValidSender = validateSender(transaction); - if (maybeValidSender.isEmpty()) { - return validateRecipient(transaction); - } - return maybeValidSender; + final Optional errMsg = + validateSender(transaction).or(() -> validateRecipient(transaction)); + errMsg.ifPresent(reason -> reportRejectedTransaction(transaction, reason)); + return errMsg; } private Optional validateRecipient(final Transaction transaction) { @@ -86,4 +90,19 @@ private Optional validateSender(final Transaction transaction) { } return Optional.empty(); } + + private void reportRejectedTransaction(final Transaction transaction, final String reason) { + rejectedTxJsonRpcManager.ifPresent( + jsonRpcManager -> { + final String jsonRpcCall = + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + transaction, + Instant.now(), + Optional.empty(), // block number is not available + reason, + List.of()); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); + }); + } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidator.java index 44eba275..7ecaf125 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidator.java @@ -14,11 +14,15 @@ */ package net.consensys.linea.sequencer.txpoolvalidation.validators; +import java.time.Instant; +import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; +import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidator; @@ -27,6 +31,7 @@ @RequiredArgsConstructor public class CalldataValidator implements PluginTransactionPoolValidator { final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf; + final Optional rejectedTxJsonRpcManager; @Override public Optional validateTransaction( @@ -36,8 +41,24 @@ public Optional validateTransaction( "Calldata of transaction is greater than the allowed max of " + txPoolValidatorConf.maxTxCalldataSize(); log.debug(errMsg); + reportRejectedTransaction(transaction, errMsg); return Optional.of(errMsg); } return Optional.empty(); } + + private void reportRejectedTransaction(final Transaction transaction, final String reason) { + rejectedTxJsonRpcManager.ifPresent( + jsonRpcManager -> { + final String jsonRpcCall = + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + transaction, + Instant.now(), + Optional.empty(), // block number is not available + reason, + List.of()); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); + }); + } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidator.java index f86e2844..7e2f9042 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidator.java @@ -14,11 +14,15 @@ */ package net.consensys.linea.sequencer.txpoolvalidation.validators; +import java.time.Instant; +import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; +import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidator; @@ -30,6 +34,7 @@ @RequiredArgsConstructor public class GasLimitValidator implements PluginTransactionPoolValidator { final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf; + final Optional rejectedTxJsonRpcManager; @Override public Optional validateTransaction( @@ -39,8 +44,24 @@ public Optional validateTransaction( "Gas limit of transaction is greater than the allowed max of " + txPoolValidatorConf.maxTxGasLimit(); log.debug(errMsg); + reportRejectedTransaction(transaction, errMsg); return Optional.of(errMsg); } return Optional.empty(); } + + private void reportRejectedTransaction(final Transaction transaction, final String reason) { + rejectedTxJsonRpcManager.ifPresent( + jsonRpcManager -> { + final String jsonRpcCall = + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + transaction, + Instant.now(), + Optional.empty(), // block number is not available + reason, + List.of()); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); + }); + } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidator.java index 74040fdb..8b91452f 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidator.java @@ -14,11 +14,15 @@ */ package net.consensys.linea.sequencer.txpoolvalidation.validators; +import java.time.Instant; +import java.util.List; import java.util.Optional; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.bl.TransactionProfitabilityCalculator; import net.consensys.linea.config.LineaProfitabilityConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; +import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder; import org.apache.tuweni.units.bigints.UInt256s; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.datatypes.Wei; @@ -37,15 +41,18 @@ public class ProfitabilityValidator implements PluginTransactionPoolValidator { final BlockchainService blockchainService; final LineaProfitabilityConfiguration profitabilityConf; final TransactionProfitabilityCalculator profitabilityCalculator; + final Optional rejectedTxJsonRpcManager; public ProfitabilityValidator( final BesuConfiguration besuConfiguration, final BlockchainService blockchainService, - final LineaProfitabilityConfiguration profitabilityConf) { + final LineaProfitabilityConfiguration profitabilityConf, + final Optional rejectedTxJsonRpcManager) { this.besuConfiguration = besuConfiguration; this.blockchainService = blockchainService; this.profitabilityConf = profitabilityConf; this.profitabilityCalculator = new TransactionProfitabilityCalculator(profitabilityConf); + this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager; } @Override @@ -61,16 +68,19 @@ public Optional validateTransaction( .getNextBlockBaseFee() .orElseThrow(() -> new RuntimeException("We only support a base fee market")); - return profitabilityCalculator.isProfitable( - "Txpool", - transaction, - profitabilityConf.txPoolMinMargin(), - baseFee, - calculateUpfrontGasPrice(transaction, baseFee), - transaction.getGasLimit(), - besuConfiguration.getMinGasPrice()) - ? Optional.empty() - : Optional.of("Gas price too low"); + final Optional errMsg = + profitabilityCalculator.isProfitable( + "Txpool", + transaction, + profitabilityConf.txPoolMinMargin(), + baseFee, + calculateUpfrontGasPrice(transaction, baseFee), + transaction.getGasLimit(), + besuConfiguration.getMinGasPrice()) + ? Optional.empty() + : Optional.of("Gas price too low"); + errMsg.ifPresent(s -> reportRejectedTransaction(transaction, s)); + return errMsg; } return Optional.empty(); @@ -88,4 +98,19 @@ private Wei calculateUpfrontGasPrice(final Transaction transaction, final Wei ba baseFee.add(Wei.fromQuantity(transaction.getMaxPriorityFeePerGas().get())))) .orElseGet(() -> Wei.fromQuantity(transaction.getGasPrice().get())); } + + private void reportRejectedTransaction(final Transaction transaction, final String reason) { + rejectedTxJsonRpcManager.ifPresent( + jsonRpcManager -> { + final String jsonRpcCall = + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + transaction, + Instant.now(), + Optional.empty(), // block number is not available + reason, + List.of()); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); + }); + } } diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java index e3a7c2a8..c2abbf49 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java @@ -17,11 +17,15 @@ import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.ModuleLineCountResult.MODULE_NOT_DEFINED; import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.ModuleLineCountResult.TX_MODULE_LINE_COUNT_OVERFLOW; +import java.time.Instant; +import java.util.List; import java.util.Map; import java.util.Optional; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; +import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder; import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration; import net.consensys.linea.sequencer.modulelimit.ModuleLimitsValidationResult; import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator; @@ -44,18 +48,21 @@ public class SimulationValidator implements PluginTransactionPoolValidator { private final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf; private final Map moduleLineLimitsMap; private final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration; + private final Optional rejectedTxJsonRpcManager; public SimulationValidator( final BlockchainService blockchainService, final TransactionSimulationService transactionSimulationService, final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf, final Map moduleLineLimitsMap, - final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration) { + final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, + final Optional rejectedTxJsonRpcManager) { this.blockchainService = blockchainService; this.transactionSimulationService = transactionSimulationService; this.txPoolValidatorConf = txPoolValidatorConf; this.moduleLineLimitsMap = moduleLineLimitsMap; this.l1L2BridgeConfiguration = l1L2BridgeConfiguration; + this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager; } @Override @@ -91,7 +98,9 @@ public Optional validateTransaction( transaction, isLocal, hasPriority, maybeSimulationResults, moduleLimitResult); if (moduleLimitResult.getResult() != ModuleLineCountValidator.ModuleLineCountResult.VALID) { - return Optional.of(handleModuleOverLimit(transaction, moduleLimitResult)); + final String reason = handleModuleOverLimit(transaction, moduleLimitResult); + reportRejectedTransaction(transaction, reason); + return Optional.of(reason); } if (maybeSimulationResults.isPresent()) { @@ -101,6 +110,7 @@ public Optional validateTransaction( "Invalid transaction" + simulationResult.getInvalidReason().map(ir -> ": " + ir).orElse(""); log.debug(errMsg); + reportRejectedTransaction(transaction, errMsg); return Optional.of(errMsg); } if (!simulationResult.isSuccessful()) { @@ -111,6 +121,7 @@ public Optional validateTransaction( .map(rr -> ": " + rr.toHexString()) .orElse(""); log.debug(errMsg); + reportRejectedTransaction(transaction, errMsg); return Optional.of(errMsg); } } @@ -127,6 +138,21 @@ public Optional validateTransaction( return Optional.empty(); } + private void reportRejectedTransaction(final Transaction transaction, final String reason) { + rejectedTxJsonRpcManager.ifPresent( + jsonRpcManager -> { + final String jsonRpcCall = + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + transaction, + Instant.now(), + Optional.empty(), // block number is not available + reason, + List.of()); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); + }); + } + private void logSimulationResult( final Transaction transaction, final boolean isLocal, 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 1ca96d48..021758ef 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 @@ -22,6 +22,7 @@ import com.google.auto.service.AutoService; import lombok.extern.slf4j.Slf4j; import net.consensys.linea.AbstractLineaRequiredPlugin; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import net.consensys.linea.config.LineaTransactionSelectorConfiguration; import net.consensys.linea.jsonrpc.JsonRpcManager; import org.hyperledger.besu.plugin.BesuContext; @@ -81,9 +82,17 @@ public void start() { super.start(); final LineaTransactionSelectorConfiguration txSelectorConfiguration = transactionSelectorConfiguration(); + final LineaRejectedTxReportingConfiguration lineaRejectedTxReportingConfiguration = + rejectedTxReportingConfiguration(); rejectedTxJsonRpcManager = - Optional.ofNullable(txSelectorConfiguration.rejectedTxEndpoint()) - .map(endpoint -> new JsonRpcManager(besuConfiguration.getDataPath(), endpoint).start()); + Optional.ofNullable(lineaRejectedTxReportingConfiguration.rejectedTxEndpoint()) + .map( + endpoint -> + new JsonRpcManager( + "linea-tx-selector-plugin", + besuConfiguration.getDataPath(), + lineaRejectedTxReportingConfiguration) + .start()); transactionSelectionService.registerPluginTransactionSelectorFactory( new LineaTransactionSelectorFactory( blockchainService, 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 d532501e..5cc75976 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 @@ -160,9 +160,14 @@ public void onTransactionNotSelected( rejectedTxJsonRpcManager.ifPresent( jsonRpcManager -> { if (transactionSelectionResult.discard()) { - jsonRpcManager.submitNewJsonRpcCall( - JsonRpcRequestBuilder.buildRejectedTxRequest( - evaluationContext, transactionSelectionResult, Instant.now())); + jsonRpcManager.submitNewJsonRpcCallAsync( + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + jsonRpcManager.getNodeType(), + evaluationContext.getPendingTransaction().getTransaction(), + Instant.now(), + Optional.of(evaluationContext.getPendingBlockHeader().getNumber()), + transactionSelectionResult.toString(), + List.of())); } }); } diff --git a/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java b/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java new file mode 100644 index 00000000..057cdf6d --- /dev/null +++ b/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java @@ -0,0 +1,131 @@ +/* + * 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.config; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.net.MalformedURLException; +import java.net.URI; + +import org.hyperledger.besu.plugin.services.PicoCLIOptions; +import org.hyperledger.besu.services.PicoCLIOptionsImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; +import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +class LineaRejectedTxReportingCliOptionsTest { + + @Command + static final class MockLineaBesuCommand { + @Option(names = "--mock-option") + String mockOption; + } + + private MockLineaBesuCommand command; + private LineaRejectedTxReportingCliOptions lineaRejectedTxReportingCliOptions; + private CommandLine commandLine; + private PicoCLIOptions picoCliService; + + @BeforeEach + public void setup() { + command = new MockLineaBesuCommand(); + commandLine = new CommandLine(command); + picoCliService = new PicoCLIOptionsImpl(commandLine); + + lineaRejectedTxReportingCliOptions = LineaRejectedTxReportingCliOptions.create(); + picoCliService.addPicoCLIOptions("linea", lineaRejectedTxReportingCliOptions); + } + + @Test + void emptyLineaRejectedTxReportingCliOptions() { + commandLine.parseArgs("--mock-option", "mockValue"); + + assertThat(command.mockOption).isEqualTo("mockValue"); + assertThat(lineaRejectedTxReportingCliOptions.dependentOptions).isNull(); + } + + @ParameterizedTest + @EnumSource(LineaNodeType.class) + void lineaRejectedTxOptionBothOptionsRequired(final LineaNodeType lineaNodeType) + throws MalformedURLException { + commandLine.parseArgs( + "--plugin-linea-rejected-tx-endpoint", + "http://localhost:8080", + "--plugin-linea-node-type", + lineaNodeType.name()); + + assertThat(lineaRejectedTxReportingCliOptions.dependentOptions.rejectedTxEndpoint) + .isEqualTo(URI.create("http://localhost:8080").toURL()); + assertThat(lineaRejectedTxReportingCliOptions.dependentOptions.lineaNodeType) + .isEqualTo(lineaNodeType); + } + + @Test + void lineaRejectedTxReportingCliOptionsOnlyEndpointCauseException() { + assertThatExceptionOfType(CommandLine.ParameterException.class) + .isThrownBy( + () -> + commandLine.parseArgs( + "--plugin-linea-rejected-tx-endpoint", "http://localhost:8080")) + .withMessageContaining( + "Error: Missing required argument(s): --plugin-linea-node-type="); + } + + @Test + void lineaRejectedTxReportingCliOptionsOnlyNodeTypeCauseException() { + assertThatExceptionOfType(CommandLine.ParameterException.class) + .isThrownBy( + () -> commandLine.parseArgs("--plugin-linea-node-type", LineaNodeType.SEQUENCER.name())) + .withMessageContaining( + "Error: Missing required argument(s): --plugin-linea-rejected-tx-endpoint="); + } + + @Test + void lineaRejectedTxReportingInvalidNodeTypeCauseException() { + assertThatExceptionOfType(CommandLine.ParameterException.class) + .isThrownBy( + () -> + commandLine.parseArgs( + "--plugin-linea-rejected-tx-endpoint", + "http://localhost:8080", + "--plugin-linea-node-type", + "INVALID_NODE_TYPE")) + .withMessageContaining( + "Invalid value for option '--plugin-linea-node-type': expected one of [SEQUENCER, RPC, P2P] (case-sensitive) but was 'INVALID_NODE_TYPE'"); + } + + @ParameterizedTest + @ValueSource(strings = {"", "http://localhost:8080:8080", "invalid"}) + void lineaRejectedTxReportingCliOptionsInvalidEndpointCauseException(final String endpoint) { + assertThatExceptionOfType(CommandLine.ParameterException.class) + .isThrownBy( + () -> + commandLine.parseArgs( + "--plugin-linea-rejected-tx-endpoint", + endpoint, + "--plugin-linea-node-type", + "SEQUENCER")) + .withMessageContaining( + "Invalid value for option '--plugin-linea-rejected-tx-endpoint': cannot convert '" + + endpoint + + "' to URL (java.net.MalformedURLException:"); + } +} diff --git a/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerStartTest.java b/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerStartTest.java index 98c6be2a..5601d35b 100644 --- a/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerStartTest.java +++ b/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerStartTest.java @@ -30,14 +30,15 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; +import java.util.List; +import java.util.Optional; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; -import net.consensys.linea.sequencer.txselection.selectors.TestTransactionEvaluationContext; +import net.consensys.linea.config.LineaNodeType; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import org.apache.tuweni.bytes.Bytes; -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.TransactionSelectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -53,35 +54,42 @@ public class JsonRpcManagerStartTest { @TempDir private Path tempDataDir; private JsonRpcManager jsonRpcManager; private final Bytes randomEncodedBytes = Bytes.random(32); - @Mock private PendingTransaction pendingTransaction; - @Mock private ProcessableBlockHeader pendingBlockHeader; @Mock private Transaction transaction; + static final String PLUGIN_IDENTIFIER = "linea-start-test-plugin"; @BeforeEach void init(final WireMockRuntimeInfo wmInfo) throws IOException { // create temp directories - final Path rejectedTxDir = tempDataDir.resolve("rej_tx_rpc"); - Files.createDirectories(rejectedTxDir); + final Path jsonRpcDir = + tempDataDir.resolve(JsonRpcManager.JSON_RPC_DIR).resolve(PLUGIN_IDENTIFIER); + Files.createDirectories(jsonRpcDir); // mock stubbing - when(pendingBlockHeader.getNumber()).thenReturn(1L); - when(pendingTransaction.getTransaction()).thenReturn(transaction); when(transaction.encoded()).thenReturn(randomEncodedBytes); // save rejected transaction in tempDataDir so that they are processed by the // JsonRpcManager.start for (int i = 0; i < 3; i++) { - final TestTransactionEvaluationContext context = - new TestTransactionEvaluationContext(pendingBlockHeader, pendingTransaction); final TransactionSelectionResult result = TransactionSelectionResult.invalid("test" + i); final Instant timestamp = Instant.now(); final String jsonRpcCall = - JsonRpcRequestBuilder.buildRejectedTxRequest(context, result, timestamp); + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + LineaNodeType.SEQUENCER, + transaction, + timestamp, + Optional.of(1L), + result.toString(), + List.of()); - JsonRpcManager.saveJsonToDir(jsonRpcCall, rejectedTxDir); + JsonRpcManager.saveJsonToDir(jsonRpcCall, jsonRpcDir); } - jsonRpcManager = new JsonRpcManager(tempDataDir, URI.create(wmInfo.getHttpBaseUrl())); + final LineaRejectedTxReportingConfiguration config = + LineaRejectedTxReportingConfiguration.builder() + .rejectedTxEndpoint(URI.create(wmInfo.getHttpBaseUrl()).toURL()) + .lineaNodeType(LineaNodeType.SEQUENCER) + .build(); + jsonRpcManager = new JsonRpcManager(PLUGIN_IDENTIFIER, tempDataDir, config); } @AfterEach @@ -90,7 +98,7 @@ void cleanup() { } @Test - void existingJsonRpcFilesAreProcessedOnStart() throws InterruptedException { + void existingJsonRpcFilesAreProcessedOnStart() { stubFor( post(urlEqualTo("/")) .willReturn( diff --git a/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerTest.java b/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerTest.java index d0f567c9..b73845aa 100644 --- a/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerTest.java +++ b/sequencer/src/test/java/net/consensys/linea/jsonrpc/JsonRpcManagerTest.java @@ -29,21 +29,23 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; +import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import com.github.tomakehurst.wiremock.http.Fault; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; import com.github.tomakehurst.wiremock.stubbing.Scenario; -import net.consensys.linea.sequencer.txselection.selectors.TestTransactionEvaluationContext; +import net.consensys.linea.config.LineaNodeType; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import org.apache.tuweni.bytes.Bytes; -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.TransactionSelectionResult; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -56,21 +58,22 @@ @WireMockTest @ExtendWith(MockitoExtension.class) class JsonRpcManagerTest { + static final String PLUGIN_IDENTIFIER = "linea-json-test-plugin"; @TempDir private Path tempDataDir; private JsonRpcManager jsonRpcManager; private final Bytes randomEncodedBytes = Bytes.random(32); - @Mock private PendingTransaction pendingTransaction; - @Mock private ProcessableBlockHeader pendingBlockHeader; @Mock private Transaction transaction; @BeforeEach - void init(final WireMockRuntimeInfo wmInfo) { + void init(final WireMockRuntimeInfo wmInfo) throws MalformedURLException { // mock stubbing - when(pendingBlockHeader.getNumber()).thenReturn(1L); - when(pendingTransaction.getTransaction()).thenReturn(transaction); when(transaction.encoded()).thenReturn(randomEncodedBytes); - - jsonRpcManager = new JsonRpcManager(tempDataDir, URI.create(wmInfo.getHttpBaseUrl())); + final LineaRejectedTxReportingConfiguration config = + LineaRejectedTxReportingConfiguration.builder() + .rejectedTxEndpoint(URI.create(wmInfo.getHttpBaseUrl()).toURL()) + .lineaNodeType(LineaNodeType.SEQUENCER) + .build(); + jsonRpcManager = new JsonRpcManager(PLUGIN_IDENTIFIER, tempDataDir, config); jsonRpcManager.start(); } @@ -80,7 +83,7 @@ void cleanup() { } @Test - void rejectedTxIsReported() throws InterruptedException { + void rejectedTxIsReported() { // json-rpc stubbing stubFor( post(urlEqualTo("/")) @@ -91,15 +94,20 @@ void rejectedTxIsReported() throws InterruptedException { .withBody( "{\"jsonrpc\":\"2.0\",\"result\":{ \"status\": \"SAVED\"},\"id\":1}"))); - final TestTransactionEvaluationContext context = - new TestTransactionEvaluationContext(pendingBlockHeader, pendingTransaction); final TransactionSelectionResult result = TransactionSelectionResult.invalid("test"); final Instant timestamp = Instant.now(); // method under test final String jsonRpcCall = - JsonRpcRequestBuilder.buildRejectedTxRequest(context, result, timestamp); - jsonRpcManager.submitNewJsonRpcCall(jsonRpcCall); + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + LineaNodeType.SEQUENCER, + transaction, + timestamp, + Optional.of(1L), + result.maybeInvalidReason().orElse(""), + List.of()); + + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); // Use Awaitility to wait for the condition to be met await() @@ -137,17 +145,21 @@ void firstCallErrorSecondCallSuccessScenario() throws InterruptedException, IOEx "{\"jsonrpc\":\"2.0\",\"result\":{ \"status\": \"SAVED\"},\"id\":1}"))); // Prepare test data - final TestTransactionEvaluationContext context = - new TestTransactionEvaluationContext(pendingBlockHeader, pendingTransaction); final TransactionSelectionResult result = TransactionSelectionResult.invalid("test"); final Instant timestamp = Instant.now(); // Generate JSON-RPC call final String jsonRpcCall = - JsonRpcRequestBuilder.buildRejectedTxRequest(context, result, timestamp); + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + LineaNodeType.SEQUENCER, + transaction, + timestamp, + Optional.of(1L), + result.maybeInvalidReason().orElse(""), + List.of()); // Submit the call, the scheduler will retry the failed call - jsonRpcManager.submitNewJsonRpcCall(jsonRpcCall); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); // Use Awaitility to wait for the condition to be met await() @@ -160,7 +172,8 @@ void firstCallErrorSecondCallSuccessScenario() throws InterruptedException, IOEx // Verify that the JSON file no longer exists in the directory (as the second call was // successful) - Path rejTxRpcDir = tempDataDir.resolve("rej_tx_rpc"); + final Path rejTxRpcDir = + tempDataDir.resolve(JsonRpcManager.JSON_RPC_DIR).resolve(PLUGIN_IDENTIFIER); try (Stream files = Files.list(rejTxRpcDir)) { long fileCount = files.filter(path -> path.toString().endsWith(".json")).count(); assertThat(fileCount).isEqualTo(0); @@ -168,7 +181,7 @@ void firstCallErrorSecondCallSuccessScenario() throws InterruptedException, IOEx } @Test - void serverRespondingWithErrorScenario() throws InterruptedException, IOException { + void serverRespondingWithErrorScenario() throws IOException { // Stub for error response stubFor( post(urlEqualTo("/")) @@ -180,17 +193,21 @@ void serverRespondingWithErrorScenario() throws InterruptedException, IOExceptio "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":-32000,\"message\":\"Internal error\"},\"id\":1}"))); // Prepare test data - final TestTransactionEvaluationContext context = - new TestTransactionEvaluationContext(pendingBlockHeader, pendingTransaction); final TransactionSelectionResult result = TransactionSelectionResult.invalid("test"); final Instant timestamp = Instant.now(); // Generate JSON-RPC call final String jsonRpcCall = - JsonRpcRequestBuilder.buildRejectedTxRequest(context, result, timestamp); + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + LineaNodeType.SEQUENCER, + transaction, + timestamp, + Optional.of(1L), + result.maybeInvalidReason().orElse(""), + List.of()); // Submit the call - jsonRpcManager.submitNewJsonRpcCall(jsonRpcCall); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); // Use Awaitility to wait for the condition to be met await() @@ -202,7 +219,8 @@ void serverRespondingWithErrorScenario() throws InterruptedException, IOExceptio postRequestedFor(urlEqualTo("/")).withRequestBody(equalToJson(jsonRpcCall)))); // Verify that the JSON file still exists in the directory (as the call was unsuccessful) - final Path rejTxRpcDir = tempDataDir.resolve("rej_tx_rpc"); + final Path rejTxRpcDir = + tempDataDir.resolve(JsonRpcManager.JSON_RPC_DIR).resolve(PLUGIN_IDENTIFIER); try (Stream files = Files.list(rejTxRpcDir)) { long fileCount = files.filter(path -> path.toString().endsWith(".json")).count(); assertThat(fileCount).as("JSON file should exist as server responded with error").isOne(); @@ -242,17 +260,21 @@ void firstTwoCallsErrorThenLastCallSuccessScenario() throws InterruptedException "{\"jsonrpc\":\"2.0\",\"result\":{ \"status\": \"SAVED\"},\"id\":1}"))); // Prepare test data - final TestTransactionEvaluationContext context = - new TestTransactionEvaluationContext(pendingBlockHeader, pendingTransaction); final TransactionSelectionResult result = TransactionSelectionResult.invalid("test"); final Instant timestamp = Instant.now(); // Generate JSON-RPC call final String jsonRpcCall = - JsonRpcRequestBuilder.buildRejectedTxRequest(context, result, timestamp); + JsonRpcRequestBuilder.generateSaveRejectedTxJsonRpc( + LineaNodeType.SEQUENCER, + transaction, + timestamp, + Optional.of(1L), + result.maybeInvalidReason().orElse(""), + List.of()); // Submit the call, the scheduler will retry the failed calls - jsonRpcManager.submitNewJsonRpcCall(jsonRpcCall); + jsonRpcManager.submitNewJsonRpcCallAsync(jsonRpcCall); // Use Awaitility to wait for the condition to be met await() @@ -265,7 +287,8 @@ void firstTwoCallsErrorThenLastCallSuccessScenario() throws InterruptedException // Verify that the JSON file no longer exists in the directory (as the second call was // successful) - Path rejTxRpcDir = tempDataDir.resolve("rej_tx_rpc"); + final Path rejTxRpcDir = + tempDataDir.resolve(JsonRpcManager.JSON_RPC_DIR).resolve(PLUGIN_IDENTIFIER); try (Stream files = Files.list(rejTxRpcDir)) { long fileCount = files.filter(path -> path.toString().endsWith(".json")).count(); assertThat(fileCount).isEqualTo(0); diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidatorTest.java index c2f25f68..85bc1b3e 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/AllowedAddressValidatorTest.java @@ -40,7 +40,7 @@ public class AllowedAddressValidatorTest { @BeforeEach public void initialize() { Set
denied = Set.of(DENIED); - allowedAddressValidator = new AllowedAddressValidator(denied); + allowedAddressValidator = new AllowedAddressValidator(denied, Optional.empty()); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidatorTest.java index fc775580..e30a6d5f 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/CalldataValidatorTest.java @@ -38,7 +38,8 @@ public void initialize() { new CalldataValidator( LineaTransactionPoolValidatorCliOptions.create().toDomainObject().toBuilder() .maxTxCalldataSize(MAX_TX_CALLDATA_SIZE) - .build()); + .build(), + Optional.empty()); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidatorTest.java index 219e62f4..e7c79907 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/GasLimitValidatorTest.java @@ -38,7 +38,8 @@ public void initialize() { new GasLimitValidator( LineaTransactionPoolValidatorCliOptions.create().toDomainObject().toBuilder() .maxTxGasLimit(MAX_TX_GAS_LIMIT) - .build()); + .build(), + Optional.empty()); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidatorTest.java index 3178a5ec..de333edb 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/ProfitabilityValidatorTest.java @@ -87,7 +87,8 @@ public void initialize() { profitabilityConfBuilder .txPoolCheckP2pEnabled(true) .txPoolCheckApiEnabled(true) - .build()); + .build(), + Optional.empty()); profitabilityValidatorNever = new ProfitabilityValidator( @@ -96,7 +97,8 @@ public void initialize() { profitabilityConfBuilder .txPoolCheckP2pEnabled(false) .txPoolCheckApiEnabled(false) - .build()); + .build(), + Optional.empty()); profitabilityValidatorOnlyApi = new ProfitabilityValidator( @@ -105,7 +107,8 @@ public void initialize() { profitabilityConfBuilder .txPoolCheckP2pEnabled(false) .txPoolCheckApiEnabled(true) - .build()); + .build(), + Optional.empty()); profitabilityValidatorOnlyP2p = new ProfitabilityValidator( @@ -114,7 +117,8 @@ public void initialize() { profitabilityConfBuilder .txPoolCheckP2pEnabled(true) .txPoolCheckApiEnabled(false) - .build()); + .build(), + Optional.empty()); } @Test diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java index 8bb71b86..cd1e9ed1 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java @@ -15,22 +15,40 @@ package net.consensys.linea.sequencer.txpoolvalidation.validators; +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.exactly; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.IOException; import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import net.consensys.linea.config.LineaNodeType; +import net.consensys.linea.config.LineaRejectedTxReportingConfiguration; import net.consensys.linea.config.LineaTracerConfiguration; import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration; +import net.consensys.linea.jsonrpc.JsonRpcManager; import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration; import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator; import net.consensys.linea.sequencer.txselection.selectors.TraceLineLimitTransactionSelectorTest; @@ -44,6 +62,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -54,6 +73,7 @@ @Slf4j @RequiredArgsConstructor +@WireMockTest @ExtendWith(MockitoExtension.class) public class SimulationValidatorTest { private static final String MODULE_LINE_LIMITS_RESOURCE_NAME = "/sequencer/line-limits.toml"; @@ -87,7 +107,8 @@ public class SimulationValidatorTest { @Mock BlockchainService blockchainService; @Mock TransactionSimulationService transactionSimulationService; - + private JsonRpcManager jsonRpcManager; + @TempDir private Path tempDataDir; @TempDir static Path tempDir; static Path lineLimitsConfPath; @@ -101,7 +122,7 @@ public static void beforeAll() throws IOException { } @BeforeEach - public void initialize() { + public void initialize(final WireMockRuntimeInfo wmInfo) throws MalformedURLException { final var tracerConf = LineaTracerConfiguration.builder() .moduleLimitsFilePath(lineLimitsConfPath.toString()) @@ -110,6 +131,29 @@ public void initialize() { final var blockHeader = mock(BlockHeader.class); when(blockHeader.getBaseFee()).thenReturn(Optional.of(BASE_FEE)); when(blockchainService.getChainHeadHeader()).thenReturn(blockHeader); + + final var rejectedTxReportingConf = + LineaRejectedTxReportingConfiguration.builder() + .rejectedTxEndpoint(URI.create(wmInfo.getHttpBaseUrl()).toURL()) + .lineaNodeType(LineaNodeType.P2P) + .build(); + jsonRpcManager = + new JsonRpcManager("simulation-test", tempDataDir, rejectedTxReportingConf).start(); + + // rejected tx json-rpc stubbing + stubFor( + post(urlEqualTo("/")) + .willReturn( + aResponse() + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody( + "{\"jsonrpc\":\"2.0\",\"result\":{ \"status\": \"SAVED\"},\"id\":1}"))); + } + + @AfterEach + void cleanup() { + jsonRpcManager.shutdown(); } private SimulationValidator createSimulationValidator( @@ -127,7 +171,8 @@ private SimulationValidator createSimulationValidator( LineaL1L2BridgeSharedConfiguration.builder() .contract(BRIDGE_CONTRACT) .topic(BRIDGE_LOG_TOPIC) - .build()); + .build(), + Optional.of(jsonRpcManager)); } @Test @@ -147,7 +192,7 @@ public void successfulTransactionIsValid() { } @Test - public void moduleLineCountOverflowTransactionIsInvalid() { + public void moduleLineCountOverflowTransactionIsInvalidAndReported() { lineCountLimits.put("EXT", 5); final var simulationValidator = createSimulationValidator(lineCountLimits, true, false); final org.hyperledger.besu.ethereum.core.Transaction transaction = @@ -160,8 +205,25 @@ public void moduleLineCountOverflowTransactionIsInvalid() { .value(Wei.ONE) .signature(FAKE_SIGNATURE) .build(); + final var expectedReasonMessage = + "Transaction 0xbf668c5dc926c008d5b34f347e1842b94911b46f4a36b668812f821e20303322 line count for module EXT=7 is above the limit 5"; assertThat(simulationValidator.validateTransaction(transaction, true, false)) - .contains( - "Transaction 0xbf668c5dc926c008d5b34f347e1842b94911b46f4a36b668812f821e20303322 line count for module EXT=7 is above the limit 5"); + .contains(expectedReasonMessage); + + // assert that wiremock received 1 post request for rejected tx. + // Use Awaitility to wait for the condition to be met + await() + .atMost(6, SECONDS) + .untilAsserted( + () -> + verify( + exactly(1), + postRequestedFor(urlEqualTo("/")) + .withRequestBody( + matchingJsonPath( + "$.params.txRejectionStage", equalTo(LineaNodeType.P2P.name()))) + .withRequestBody( + matchingJsonPath( + "$.params.reasonMessage", equalTo(expectedReasonMessage))))); } } From 29024106ecced8ee9c49a07810972b8afecb4021 Mon Sep 17 00:00:00 2001 From: Usman Saleem Date: Tue, 8 Oct 2024 19:00:58 +1000 Subject: [PATCH 5/6] fix: Validate rejected-tx cli options without ArgGroup (#95) Removed PicoCli ArgGroup validation as it didn't work in Besu with config file parsing which uses DefaultValueProvider. Instead, validate rejected tx cli options in the toDomainObject method. Enforce the rule that node type is required when endpoint is specified. If only node type is specified, we need no custom validation as we are only enabling reporting when endpoint is specified. --- .../LineaRejectedTxReportingCliOptions.java | 63 +++++++------------ ...ineaRejectedTxReportingCliOptionsTest.java | 40 ++++++------ 2 files changed, 42 insertions(+), 61 deletions(-) diff --git a/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java index 53b84762..cbdce8af 100644 --- a/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java +++ b/sequencer/src/main/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptions.java @@ -15,11 +15,9 @@ package net.consensys.linea.config; import java.net.URL; -import java.util.Optional; import com.google.common.base.MoreObjects; import net.consensys.linea.plugins.LineaCliOptions; -import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Option; /** The Linea Rejected Transaction Reporting CLI options. */ @@ -35,28 +33,21 @@ public class LineaRejectedTxReportingCliOptions implements LineaCliOptions { /** The Linea node type. */ public static final String LINEA_NODE_TYPE = "--plugin-linea-node-type"; - @ArgGroup(exclusive = false) - DependentOptions dependentOptions; // will be null if no options from this group are specified - - static class DependentOptions { - @Option( - names = {REJECTED_TX_ENDPOINT}, - hidden = true, - required = true, // required within the group - paramLabel = "", - description = - "Endpoint URI for reporting rejected transactions. Specify a valid URI to enable reporting.") - URL rejectedTxEndpoint = null; - - @Option( - names = {LINEA_NODE_TYPE}, - hidden = true, - required = true, // required within the group - paramLabel = "", - description = - "Linea Node type to use when reporting rejected transactions. (default: ${DEFAULT-VALUE}. Valid values: ${COMPLETION-CANDIDATES})") - LineaNodeType lineaNodeType = null; - } + @Option( + names = {REJECTED_TX_ENDPOINT}, + hidden = true, + paramLabel = "", + description = + "Endpoint URI for reporting rejected transactions. Specify a valid URI to enable reporting.") + URL rejectedTxEndpoint = null; + + @Option( + names = {LINEA_NODE_TYPE}, + hidden = true, + paramLabel = "", + description = + "Linea Node type to use when reporting rejected transactions. (Valid values: ${COMPLETION-CANDIDATES})") + LineaNodeType lineaNodeType = null; /** Default constructor. */ private LineaRejectedTxReportingCliOptions() {} @@ -78,23 +69,19 @@ public static LineaRejectedTxReportingCliOptions create() { public static LineaRejectedTxReportingCliOptions fromConfig( final LineaRejectedTxReportingConfiguration config) { final LineaRejectedTxReportingCliOptions options = create(); - // both options are required. - if (config.rejectedTxEndpoint() != null && config.lineaNodeType() != null) { - final var depOpts = new DependentOptions(); - depOpts.rejectedTxEndpoint = config.rejectedTxEndpoint(); - depOpts.lineaNodeType = config.lineaNodeType(); - options.dependentOptions = depOpts; - } - + options.rejectedTxEndpoint = config.rejectedTxEndpoint(); + options.lineaNodeType = config.lineaNodeType(); return options; } @Override public LineaRejectedTxReportingConfiguration toDomainObject() { - final var rejectedTxEndpoint = - Optional.ofNullable(dependentOptions).map(o -> o.rejectedTxEndpoint).orElse(null); - final var lineaNodeType = - Optional.ofNullable(dependentOptions).map(o -> o.lineaNodeType).orElse(null); + // perform validation here, if endpoint is specified then node type is required. + // We can ignore node type if endpoint is not specified. + if (rejectedTxEndpoint != null && lineaNodeType == null) { + throw new IllegalArgumentException( + "Error: Missing required argument(s): " + LINEA_NODE_TYPE + "="); + } return LineaRejectedTxReportingConfiguration.builder() .rejectedTxEndpoint(rejectedTxEndpoint) @@ -104,10 +91,6 @@ public LineaRejectedTxReportingConfiguration toDomainObject() { @Override public String toString() { - final var rejectedTxEndpoint = - Optional.ofNullable(dependentOptions).map(o -> o.rejectedTxEndpoint).orElse(null); - final var lineaNodeType = - Optional.ofNullable(dependentOptions).map(o -> o.lineaNodeType).orElse(null); return MoreObjects.toStringHelper(this) .add(REJECTED_TX_ENDPOINT, rejectedTxEndpoint) diff --git a/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java b/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java index 057cdf6d..12124f17 100644 --- a/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java +++ b/sequencer/src/test/java/net/consensys/linea/config/LineaRejectedTxReportingCliOptionsTest.java @@ -16,11 +16,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatNoException; import java.net.MalformedURLException; import java.net.URI; -import org.hyperledger.besu.plugin.services.PicoCLIOptions; import org.hyperledger.besu.services.PicoCLIOptionsImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,18 +40,18 @@ static final class MockLineaBesuCommand { } private MockLineaBesuCommand command; - private LineaRejectedTxReportingCliOptions lineaRejectedTxReportingCliOptions; private CommandLine commandLine; - private PicoCLIOptions picoCliService; + private LineaRejectedTxReportingCliOptions txReportingCliOptions; @BeforeEach public void setup() { command = new MockLineaBesuCommand(); commandLine = new CommandLine(command); - picoCliService = new PicoCLIOptionsImpl(commandLine); - lineaRejectedTxReportingCliOptions = LineaRejectedTxReportingCliOptions.create(); - picoCliService.addPicoCLIOptions("linea", lineaRejectedTxReportingCliOptions); + // add mixin option before parseArgs is called + final PicoCLIOptionsImpl picoCliService = new PicoCLIOptionsImpl(commandLine); + txReportingCliOptions = LineaRejectedTxReportingCliOptions.create(); + picoCliService.addPicoCLIOptions("linea", txReportingCliOptions); } @Test @@ -59,7 +59,8 @@ void emptyLineaRejectedTxReportingCliOptions() { commandLine.parseArgs("--mock-option", "mockValue"); assertThat(command.mockOption).isEqualTo("mockValue"); - assertThat(lineaRejectedTxReportingCliOptions.dependentOptions).isNull(); + assertThat(txReportingCliOptions.rejectedTxEndpoint).isNull(); + assertThat(txReportingCliOptions.lineaNodeType).isNull(); } @ParameterizedTest @@ -72,30 +73,27 @@ void lineaRejectedTxOptionBothOptionsRequired(final LineaNodeType lineaNodeType) "--plugin-linea-node-type", lineaNodeType.name()); - assertThat(lineaRejectedTxReportingCliOptions.dependentOptions.rejectedTxEndpoint) + // parse args would not throw an exception, toDomainObject will perform the validation + assertThat(txReportingCliOptions.rejectedTxEndpoint) .isEqualTo(URI.create("http://localhost:8080").toURL()); - assertThat(lineaRejectedTxReportingCliOptions.dependentOptions.lineaNodeType) - .isEqualTo(lineaNodeType); + assertThat(txReportingCliOptions.lineaNodeType).isEqualTo(lineaNodeType); + assertThatNoException().isThrownBy(() -> txReportingCliOptions.toDomainObject()); } @Test void lineaRejectedTxReportingCliOptionsOnlyEndpointCauseException() { - assertThatExceptionOfType(CommandLine.ParameterException.class) - .isThrownBy( - () -> - commandLine.parseArgs( - "--plugin-linea-rejected-tx-endpoint", "http://localhost:8080")) + commandLine.parseArgs("--plugin-linea-rejected-tx-endpoint", "http://localhost:8080"); + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> txReportingCliOptions.toDomainObject()) .withMessageContaining( "Error: Missing required argument(s): --plugin-linea-node-type="); } @Test - void lineaRejectedTxReportingCliOptionsOnlyNodeTypeCauseException() { - assertThatExceptionOfType(CommandLine.ParameterException.class) - .isThrownBy( - () -> commandLine.parseArgs("--plugin-linea-node-type", LineaNodeType.SEQUENCER.name())) - .withMessageContaining( - "Error: Missing required argument(s): --plugin-linea-rejected-tx-endpoint="); + void lineaRejectedTxReportingCliOptionsOnlyNodeTypeParsesWithoutProblem() { + commandLine.parseArgs("--plugin-linea-node-type", LineaNodeType.SEQUENCER.name()); + assertThatNoException().isThrownBy(() -> txReportingCliOptions.toDomainObject()); } @Test From 02a2f6bce75d9cd64e95334c37ad5374bef68784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20B=C3=A9gassat?= <38285177+OlivierBBB@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:44:47 +0200 Subject: [PATCH 6/6] Provide `chainId` to `createZkTracer(...)` (#93) * fix: provide chainId to createZkTracer(...) * fix: bumped arithmetization version to 0.8.0-rc2 * Make sure chainId is present and positive Signed-off-by: Fabio Di Fabio * Set arithmetizationVersion=0.8.0-rc4 Signed-off-by: Fabio Di Fabio --------- Signed-off-by: Fabio Di Fabio Co-authored-by: Fabio Di Fabio --- gradle.properties | 4 +-- .../linea/AbstractLineaRequiredPlugin.java | 29 ++++++++++++++++++- .../linea/extradata/LineaExtraDataPlugin.java | 9 ------ .../linea/rpc/methods/LineaEstimateGas.java | 6 ++-- .../LineaEstimateGasEndpointPlugin.java | 10 ------- .../LineaTransactionPoolValidatorPlugin.java | 11 +------ .../validators/SimulationValidator.java | 7 +++-- .../LineaTransactionSelectorPlugin.java | 11 +------ .../selectors/LineaTransactionSelector.java | 6 +++- .../TraceLineLimitTransactionSelector.java | 6 +++- .../validators/SimulationValidatorTest.java | 1 + ...TraceLineLimitTransactionSelectorTest.java | 2 ++ 12 files changed, 52 insertions(+), 50 deletions(-) diff --git a/gradle.properties b/gradle.properties index f0e3c8c0..3b1a8781 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ -releaseVersion=0.8.0-rc1.1 +releaseVersion=0.8.0-rc4.1 besuVersion=24.10-delivery34 -arithmetizationVersion=0.8.0-rc1 +arithmetizationVersion=0.8.0-rc4 besuArtifactGroup=io.consensys.linea-besu distributionIdentifier=linea-sequencer distributionBaseUrl=https://artifacts.consensys.net/public/linea-besu/raw/names/linea-besu.tar.gz/versions/ \ No newline at end of file diff --git a/sequencer/src/main/java/net/consensys/linea/AbstractLineaRequiredPlugin.java b/sequencer/src/main/java/net/consensys/linea/AbstractLineaRequiredPlugin.java index c3b51351..152dd326 100644 --- a/sequencer/src/main/java/net/consensys/linea/AbstractLineaRequiredPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/AbstractLineaRequiredPlugin.java @@ -18,9 +18,11 @@ import lombok.extern.slf4j.Slf4j; import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; +import org.hyperledger.besu.plugin.services.BlockchainService; @Slf4j public abstract class AbstractLineaRequiredPlugin extends AbstractLineaPrivateOptionsPlugin { + protected BlockchainService blockchainService; /** * Linea plugins extending this class will halt startup of Besu in case of exception during @@ -34,7 +36,15 @@ public abstract class AbstractLineaRequiredPlugin extends AbstractLineaPrivateOp public void register(final BesuContext context) { super.register(context); try { - log.info("Registering Linea plugin " + this.getClass().getName()); + log.info("Registering Linea plugin {}", this.getClass().getName()); + + blockchainService = + context + .getService(BlockchainService.class) + .orElseThrow( + () -> + new RuntimeException( + "Failed to obtain BlockchainService from the BesuContext.")); doRegister(context); @@ -52,4 +62,21 @@ public void register(final BesuContext context) { * @param context */ public abstract void doRegister(final BesuContext context); + + @Override + public void beforeExternalServices() { + super.beforeExternalServices(); + + blockchainService + .getChainId() + .ifPresentOrElse( + chainId -> { + if (chainId.signum() <= 0) { + throw new IllegalArgumentException("Chain id must be greater than zero."); + } + }, + () -> { + throw new IllegalArgumentException("Chain id required"); + }); + } } 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 7fe0aa98..ed100ec3 100644 --- a/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java +++ b/sequencer/src/main/java/net/consensys/linea/extradata/LineaExtraDataPlugin.java @@ -23,7 +23,6 @@ import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.services.BesuEvents; -import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.RpcEndpointService; /** This plugin registers handlers that are activated when new blocks are imported */ @@ -33,7 +32,6 @@ public class LineaExtraDataPlugin extends AbstractLineaRequiredPlugin { public static final String NAME = "linea"; private BesuContext besuContext; private RpcEndpointService rpcEndpointService; - private BlockchainService blockchainService; @Override public Optional getName() { @@ -50,13 +48,6 @@ public void doRegister(final BesuContext context) { () -> new RuntimeException( "Failed to obtain RpcEndpointService from the BesuContext.")); - blockchainService = - context - .getService(BlockchainService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BlockchainService from the BesuContext.")); } /** diff --git a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaEstimateGas.java b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaEstimateGas.java index 34d25066..9e81b72e 100644 --- a/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaEstimateGas.java +++ b/sequencer/src/main/java/net/consensys/linea/rpc/methods/LineaEstimateGas.java @@ -270,7 +270,7 @@ private Long estimateGasUsed( final var estimateGasTracer = new EstimateGasOperationTracer(); final var chainHeadHeader = blockchainService.getChainHeadHeader(); - final var zkTracer = createZkTracer(chainHeadHeader); + final var zkTracer = createZkTracer(chainHeadHeader, blockchainService.getChainId().get()); final TracerAggregator zkAndGasTracer = TracerAggregator.create(estimateGasTracer, zkTracer); final var chainHeadHash = chainHeadHeader.getBlockHash(); @@ -491,8 +491,8 @@ private Transaction createTransactionForSimulation( return txBuilder.build(); } - private ZkTracer createZkTracer(final BlockHeader chainHeadHeader) { - var zkTracer = new ZkTracer(l1L2BridgeConfiguration); + private ZkTracer createZkTracer(final BlockHeader chainHeadHeader, final BigInteger chainId) { + var zkTracer = new ZkTracer(l1L2BridgeConfiguration, chainId); zkTracer.traceStartConflation(1L); zkTracer.traceStartBlock(chainHeadHeader); return zkTracer; 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 0ac2f2ed..6d80e523 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 @@ -24,7 +24,6 @@ import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.RpcEndpointService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; @@ -35,7 +34,6 @@ public class LineaEstimateGasEndpointPlugin extends AbstractLineaRequiredPlugin private BesuConfiguration besuConfiguration; private RpcEndpointService rpcEndpointService; private TransactionSimulationService transactionSimulationService; - private BlockchainService blockchainService; private LineaEstimateGas lineaEstimateGasMethod; /** @@ -69,14 +67,6 @@ public void doRegister(final BesuContext context) { new RuntimeException( "Failed to obtain TransactionSimulatorService from the BesuContext.")); - blockchainService = - context - .getService(BlockchainService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BlockchainService from the BesuContext.")); - lineaEstimateGasMethod = new LineaEstimateGas( besuConfiguration, transactionSimulationService, blockchainService, rpcEndpointService); 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 0db9229f..98c45653 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 @@ -34,7 +34,6 @@ import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; @@ -49,7 +48,6 @@ public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPlugin { public static final String NAME = "linea"; private BesuConfiguration besuConfiguration; - private BlockchainService blockchainService; private TransactionPoolValidatorService transactionPoolValidatorService; private TransactionSimulationService transactionSimulationService; private Optional rejectedTxJsonRpcManager = Optional.empty(); @@ -69,14 +67,6 @@ public void doRegister(final BesuContext context) { new RuntimeException( "Failed to obtain BesuConfiguration from the BesuContext.")); - blockchainService = - context - .getService(BlockchainService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BlockchainService from the BesuContext.")); - transactionPoolValidatorService = context .getService(TransactionPoolValidatorService.class) @@ -97,6 +87,7 @@ public void doRegister(final BesuContext context) { @Override public void start() { super.start(); + try (Stream lines = Files.lines( Path.of(new File(transactionPoolValidatorConfiguration().denyListPath()).toURI()))) { diff --git a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java index c2abbf49..86530ab0 100644 --- a/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java +++ b/sequencer/src/main/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidator.java @@ -17,6 +17,7 @@ import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.ModuleLineCountResult.MODULE_NOT_DEFINED; import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.ModuleLineCountResult.TX_MODULE_LINE_COUNT_OVERFLOW; +import java.math.BigInteger; import java.time.Instant; import java.util.List; import java.util.Map; @@ -86,7 +87,7 @@ public Optional validateTransaction( new ModuleLineCountValidator(moduleLineLimitsMap); final var chainHeadHeader = blockchainService.getChainHeadHeader(); - final var zkTracer = createZkTracer(chainHeadHeader); + final var zkTracer = createZkTracer(chainHeadHeader, blockchainService.getChainId().get()); final var maybeSimulationResults = transactionSimulationService.simulate( transaction, chainHeadHeader.getBlockHash(), zkTracer, true); @@ -170,8 +171,8 @@ private void logSimulationResult( .log(); } - private ZkTracer createZkTracer(final BlockHeader chainHeadHeader) { - var zkTracer = new ZkTracer(l1L2BridgeConfiguration); + private ZkTracer createZkTracer(final BlockHeader chainHeadHeader, BigInteger chainId) { + var zkTracer = new ZkTracer(l1L2BridgeConfiguration, chainId); zkTracer.traceStartConflation(1L); zkTracer.traceStartBlock(chainHeadHeader); return zkTracer; 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 021758ef..a84754e7 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,7 +28,6 @@ import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuPlugin; import org.hyperledger.besu.plugin.services.BesuConfiguration; -import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.TransactionSelectionService; /** @@ -41,7 +40,6 @@ public class LineaTransactionSelectorPlugin extends AbstractLineaRequiredPlugin { public static final String NAME = "linea"; private TransactionSelectionService transactionSelectionService; - private BlockchainService blockchainService; private Optional rejectedTxJsonRpcManager = Optional.empty(); private BesuConfiguration besuConfiguration; @@ -60,14 +58,6 @@ public void doRegister(final BesuContext context) { new RuntimeException( "Failed to obtain TransactionSelectionService from the BesuContext.")); - blockchainService = - context - .getService(BlockchainService.class) - .orElseThrow( - () -> - new RuntimeException( - "Failed to obtain BlockchainService from the BesuContext.")); - besuConfiguration = context .getService(BesuConfiguration.class) @@ -80,6 +70,7 @@ public void doRegister(final BesuContext context) { @Override public void start() { super.start(); + final LineaTransactionSelectorConfiguration txSelectorConfiguration = transactionSelectorConfiguration(); final LineaRejectedTxReportingConfiguration lineaRejectedTxReportingConfiguration = 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 5cc75976..a396b83f 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 @@ -80,7 +80,11 @@ private List createTransactionSelectors( traceLineLimitTransactionSelector = new TraceLineLimitTransactionSelector( - limitsMap, txSelectorConfiguration, l1L2BridgeConfiguration, tracerConfiguration); + blockchainService.getChainId().get(), + limitsMap, + txSelectorConfiguration, + l1L2BridgeConfiguration, + tracerConfiguration); return List.of( new MaxBlockCallDataTransactionSelector(txSelectorConfiguration.maxBlockCallDataSize()), 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 79c857e9..ed7f0675 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 @@ -19,6 +19,7 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_MODULE_LINE_COUNT_OVERFLOW_CACHED; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; +import java.math.BigInteger; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -56,6 +57,7 @@ public class TraceLineLimitTransactionSelector implements PluginTransactionSelec private static final Marker BLOCK_LINE_COUNT_MARKER = MarkerFactory.getMarker("BLOCK_LINE_COUNT"); @VisibleForTesting protected static Set overLineCountLimitCache = new LinkedHashSet<>(); private final ZkTracer zkTracer; + private final BigInteger chainId; private final String limitFilePath; private final Map moduleLimits; private final int overLimitCacheSize; @@ -63,6 +65,7 @@ public class TraceLineLimitTransactionSelector implements PluginTransactionSelec private Map currCumulatedLineCount; public TraceLineLimitTransactionSelector( + final BigInteger chainId, final Map moduleLimits, final LineaTransactionSelectorConfiguration txSelectorConfiguration, final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration, @@ -72,6 +75,7 @@ public TraceLineLimitTransactionSelector( System.exit(1); } + this.chainId = chainId; this.moduleLimits = moduleLimits; this.limitFilePath = tracerConfiguration.moduleLimitsFilePath(); this.overLimitCacheSize = txSelectorConfiguration.overLinesLimitCacheSize(); @@ -217,7 +221,7 @@ private String logTxLineCount() { private class ZkTracerWithLog extends ZkTracer { public ZkTracerWithLog(final LineaL1L2BridgeSharedConfiguration bridgeConfiguration) { - super(bridgeConfiguration); + super(bridgeConfiguration, chainId); } @Override diff --git a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java index cd1e9ed1..d8f39597 100644 --- a/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java +++ b/sequencer/src/test/java/net/consensys/linea/sequencer/txpoolvalidation/validators/SimulationValidatorTest.java @@ -131,6 +131,7 @@ public void initialize(final WireMockRuntimeInfo wmInfo) throws MalformedURLExce final var blockHeader = mock(BlockHeader.class); when(blockHeader.getBaseFee()).thenReturn(Optional.of(BASE_FEE)); when(blockchainService.getChainHeadHeader()).thenReturn(blockHeader); + when(blockchainService.getChainId()).thenReturn(Optional.of(BigInteger.ONE)); final var rejectedTxReportingConf = LineaRejectedTxReportingConfiguration.builder() 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 103eea16..37ae28a6 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 @@ -22,6 +22,7 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; @@ -250,6 +251,7 @@ private class TestableTraceLineLimitTransactionSelector final Map moduleLimits, final int overLimitCacheSize) { super( + BigInteger.ONE, moduleLimits, LineaTransactionSelectorConfiguration.builder() .overLinesLimitCacheSize(overLimitCacheSize)