Feat: integrate ZkCounter into the Sequencer (#1101)

* Support limitless ZkCounter

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Fixes

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

* Extend ATs to cover the ZkCounter

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>

---------

Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
Fabio Di Fabio
2025-06-13 12:05:46 +02:00
committed by GitHub
parent 7b77ce2a26
commit 2e607cc0e2
26 changed files with 1098 additions and 141 deletions

View File

@@ -21,7 +21,6 @@ import linea.plugin.acc.test.tests.web3j.generated.EcAdd;
import linea.plugin.acc.test.tests.web3j.generated.EcMul;
import linea.plugin.acc.test.tests.web3j.generated.EcPairing;
import linea.plugin.acc.test.tests.web3j.generated.EcRecover;
import net.consensys.linea.config.LineaTracerConfiguration;
import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Hash;
@@ -138,8 +137,7 @@ public class EcDataLimitsTest extends LineaPluginTestBase {
private static Stream<Arguments> ecPairingLimitsTestSource() {
Map<String, Integer> moduleLimits =
ModuleLineCountValidator.createLimitModules(
new LineaTracerConfiguration(getResourcePath("/moduleLimits.toml")));
ModuleLineCountValidator.createLimitModules(getResourcePath("/moduleLimits.toml"));
final int PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS =
moduleLimits.get("PRECOMPILE_ECPAIRING_FINAL_EXPONENTIATIONS");
final int PRECOMPILE_ECPAIRING_MILLER_LOOPS =
@@ -291,8 +289,7 @@ public class EcDataLimitsTest extends LineaPluginTestBase {
@Test
public void ecAddLimitTest() throws Exception {
Map<String, Integer> moduleLimits =
ModuleLineCountValidator.createLimitModules(
new LineaTracerConfiguration(getResourcePath("/moduleLimits.toml")));
ModuleLineCountValidator.createLimitModules(getResourcePath("/moduleLimits.toml"));
final int PRECOMPILE_ECADD_EFFECTIVE_CALLS =
moduleLimits.get("PRECOMPILE_ECADD_EFFECTIVE_CALLS");
@@ -384,8 +381,7 @@ public class EcDataLimitsTest extends LineaPluginTestBase {
@Test
public void ecMulLimitTest() throws Exception {
Map<String, Integer> moduleLimits =
ModuleLineCountValidator.createLimitModules(
new LineaTracerConfiguration(getResourcePath("/moduleLimits.toml")));
ModuleLineCountValidator.createLimitModules(getResourcePath("/moduleLimits.toml"));
final int PRECOMPILE_ECMUL_EFFECTIVE_CALLS =
moduleLimits.get("PRECOMPILE_ECMUL_EFFECTIVE_CALLS");
@@ -473,8 +469,7 @@ public class EcDataLimitsTest extends LineaPluginTestBase {
@Test
public void ecRecoverLimitTest() throws Exception {
Map<String, Integer> moduleLimits =
ModuleLineCountValidator.createLimitModules(
new LineaTracerConfiguration(getResourcePath("/moduleLimits.toml")));
ModuleLineCountValidator.createLimitModules(getResourcePath("/moduleLimits.toml"));
final int PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS =
moduleLimits.get("PRECOMPILE_ECRECOVER_EFFECTIVE_CALLS");

View File

@@ -0,0 +1,233 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import linea.plugin.acc.test.tests.web3j.generated.ExcludedPrecompiles;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.junit.jupiter.api.Test;
import org.web3j.abi.datatypes.generated.Bytes8;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.Hash;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;
public class ExcludedPrecompilesLimitlessTest extends LineaPluginTestBase {
private static final BigInteger GAS_LIMIT = DefaultGasProvider.GAS_LIMIT;
private static final BigInteger GAS_PRICE = DefaultGasProvider.GAS_PRICE;
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// disable line count validation to accept excluded precompile txs in the txpool
.set("--plugin-linea-tx-pool-simulation-check-api-enabled=", "false")
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/moduleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.build();
}
@Test
public void transactionsWithExcludedPrecompilesAreNotAccepted() throws Exception {
final ExcludedPrecompiles excludedPrecompiles = deployExcludedPrecompiles();
final Web3j web3j = minerNode.nodeRequests().eth();
final String contractAddress = excludedPrecompiles.getContractAddress();
// fund a new account
final var recipient = accounts.createAccount("recipient");
final var txHashFundRecipient =
accountTransactions
.createTransfer(accounts.getPrimaryBenefactor(), recipient, 10, BigInteger.valueOf(1))
.execute(minerNode.nodeRequests());
minerNode.verify(eth.expectSuccessfulTransactionReceipt(txHashFundRecipient.toHexString()));
record InvalidCall(
String senderPrivateKey, int nonce, String encodedContractCall, String expectedTraceLog) {}
final InvalidCall[] invalidCalls = {
new InvalidCall(
Accounts.GENESIS_ACCOUNT_ONE_PRIVATE_KEY,
2,
excludedPrecompiles
.callRIPEMD160("I am not allowed here".getBytes(StandardCharsets.UTF_8))
.encodeFunctionCall(),
"Tx 0xe4648fd59d4289e59b112bf60931336440d306c85c2aac5a8b0c64ab35bc55b7 line count per module: [RIP=2147483647/2147483647/1,BLAKE=0/0/1,BLOCK_L1_SIZE=235/365/1000000,MODEXP=0/0/1,BLOCK_L2_L1_LOGS=0/0/16"),
new InvalidCall(
Accounts.GENESIS_ACCOUNT_TWO_PRIVATE_KEY,
0,
encodedCallBlake2F(excludedPrecompiles),
"Tx 0x9f457b1b5244b03c54234f7f9e8225d4253135dd3c99a46dc527d115e7ea5dac line count per module: [RIP=0/0/1,BLAKE=2147483647/2147483647/1,BLOCK_L1_SIZE=462/592/1000000,MODEXP=0/0/1,BLOCK_L2_L1_LOGS=0/0/16]")
};
final var invalidTxHashes =
Arrays.stream(invalidCalls)
.map(
invalidCall -> {
// this tx must not be accepted but not mined
final RawTransaction txInvalid =
RawTransaction.createTransaction(
CHAIN_ID,
BigInteger.valueOf(invalidCall.nonce),
GAS_LIMIT.divide(BigInteger.TEN),
contractAddress,
BigInteger.ZERO,
invalidCall.encodedContractCall,
GAS_PRICE,
GAS_PRICE);
final byte[] signedTxInvalid =
TransactionEncoder.signMessage(
txInvalid, Credentials.create(invalidCall.senderPrivateKey));
final EthSendTransaction signedTxInvalidResp;
try {
signedTxInvalidResp =
web3j.ethSendRawTransaction(Numeric.toHexString(signedTxInvalid)).send();
} catch (IOException e) {
throw new RuntimeException(e);
}
assertThat(signedTxInvalidResp.hasError()).isFalse();
return signedTxInvalidResp.getTransactionHash();
})
.toList();
assertThat(getTxPoolContent()).hasSize(invalidTxHashes.size());
// transfer used as sentry to ensure a new block is mined without the invalid txs
final var transferTxHash1 =
accountTransactions
.createTransfer(recipient, accounts.getSecondaryBenefactor(), 1)
.execute(minerNode.nodeRequests());
// first sentry is mined and no tx of the bundle is mined
minerNode.verify(eth.expectSuccessfulTransactionReceipt(transferTxHash1.toHexString()));
Arrays.stream(invalidCalls)
.forEach(
invalidCall ->
minerNode.verify(
eth.expectNoTransactionReceipt(Hash.sha3(invalidCall.encodedContractCall))));
final String log = getLog();
// verify trace log contains the exclusion cause
Arrays.stream(invalidCalls)
.forEach(invalidCall -> assertThat(log).contains(invalidCall.expectedTraceLog));
}
@Test
public void invalidModExpCallsAreNotMined() throws Exception {
final var modExp = deployModExp();
final var modExpSenders = new Account[3];
final var foundTxHashes = new String[3];
for (int i = 0; i < 3; i++) {
modExpSenders[i] = accounts.createAccount("sender" + i);
foundTxHashes[i] =
accountTransactions
.createTransfer(
accounts.getSecondaryBenefactor(), modExpSenders[i], 1, BigInteger.valueOf(i))
.execute(minerNode.nodeRequests())
.toHexString();
}
Arrays.stream(foundTxHashes)
.forEach(
fundTxHash -> minerNode.verify(eth.expectSuccessfulTransactionReceipt(fundTxHash)));
final Bytes[][] invalidInputs = {
{Bytes.fromHexString("0000000000000000000000000000000000000000000000000000000000000201")},
{
Bytes.fromHexString("00000000000000000000000000000000000000000000000000000000000003"),
Bytes.fromHexString("ff")
},
{
Bytes.fromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
Bytes.fromHexString("00000000000000000000000000000000000000000000000000000000000003"),
Bytes.fromHexString("ff")
}
};
for (int i = 0; i < invalidInputs.length; i++) {
final var invalidCallTxHashes = new String[invalidInputs[i].length];
for (int j = 0; j < invalidInputs[i].length; j++) {
// use always the same nonce since we expect this tx not to be mined
final var mulmodOverflow =
encodedCallModExp(modExp, modExpSenders[j], 0, invalidInputs[i][j]);
final Web3j web3j = minerNode.nodeRequests().eth();
final EthSendTransaction resp =
web3j.ethSendRawTransaction(Numeric.toHexString(mulmodOverflow)).send();
invalidCallTxHashes[j] = resp.getTransactionHash();
}
// transfer used as sentry to ensure a new block is mined without the invalid modexp call
final var transferTxHash =
accountTransactions
.createTransfer(
accounts.getPrimaryBenefactor(),
accounts.getSecondaryBenefactor(),
1,
BigInteger.valueOf(i + 1))
.execute(minerNode.nodeRequests());
// sentry is mined and the invalid modexp txs are not
minerNode.verify(eth.expectSuccessfulTransactionReceipt(transferTxHash.toHexString()));
final var blockLog = getAndResetLog();
Arrays.stream(invalidCallTxHashes)
.forEach(
invalidCallTxHash -> {
minerNode.verify(eth.expectNoTransactionReceipt(invalidCallTxHash));
assertThat(blockLog)
.contains(
"Tx "
+ invalidCallTxHash
+ " line count for module MODEXP=2147483647 is above the limit 1, removing from the txpool");
});
}
}
private String encodedCallBlake2F(final ExcludedPrecompiles excludedPrecompiles) {
return excludedPrecompiles
.callBlake2f(
BigInteger.valueOf(12),
List.of(
Bytes32.fromHexString(
"0x48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5")
.toArrayUnsafe(),
Bytes32.fromHexString(
"0xd182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b")
.toArrayUnsafe()),
List.of(
Bytes32.fromHexString(
"0x6162630000000000000000000000000000000000000000000000000000000000")
.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe()),
List.of(Bytes8.DEFAULT.getValue(), Bytes8.DEFAULT.getValue()),
true)
.encodeFunctionCall();
}
}

View File

@@ -6,7 +6,7 @@
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test.rpc.linea;
package linea.plugin.acc.test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -14,10 +14,7 @@ import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import linea.plugin.acc.test.LineaPluginTestBase;
import linea.plugin.acc.test.TestCommandLineOptionsBuilder;
import linea.plugin.acc.test.tests.web3j.generated.ModExp;
import net.consensys.linea.config.LineaTracerConfiguration;
import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Hash;
@@ -46,8 +43,7 @@ public class ModExpLimitsTest extends LineaPluginTestBase {
@Test
public void modExpLimitTest() throws Exception {
Map<String, Integer> moduleLimits =
ModuleLineCountValidator.createLimitModules(
new LineaTracerConfiguration(getResourcePath("/moduleLimits.toml")));
ModuleLineCountValidator.createLimitModules(getResourcePath("/moduleLimits.toml"));
final int PRECOMPILE_MODEXP_EFFECTIVE_CALLS =
moduleLimits.get("PRECOMPILE_MODEXP_EFFECTIVE_CALLS");

View File

@@ -0,0 +1,75 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;
public class TransactionTraceLimitLimitlessTest extends LineaPluginTestBase {
private static final BigInteger GAS_LIMIT = DefaultGasProvider.GAS_LIMIT;
private static final BigInteger VALUE = BigInteger.ZERO;
private static final BigInteger GAS_PRICE = BigInteger.TEN.pow(9);
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/strictModuleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.build();
}
@Test
public void transactionsMinedInSeparateBlocksTest() throws Exception {
final Web3j web3j = minerNode.nodeRequests().eth();
final Credentials credentials = Credentials.create(Accounts.GENESIS_ACCOUNT_ONE_PRIVATE_KEY);
final String txData = Bytes.repeat((byte) 3, 1000).toUnprefixedHexString();
// send txs that when encoded to RLP are bigger than 1000 byte, so only one should fit in a
// block, since the
// block size limit is 2000 byte
final ArrayList<String> hashes = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
final RawTransaction transaction =
RawTransaction.createTransaction(
CHAIN_ID,
BigInteger.valueOf(i),
GAS_LIMIT,
accounts.getSecondaryBenefactor().getAddress(),
VALUE,
txData,
GAS_PRICE,
GAS_PRICE.multiply(BigInteger.TEN));
final byte[] signedTransaction = TransactionEncoder.signMessage(transaction, credentials);
final EthSendTransaction response =
web3j.ethSendRawTransaction(Numeric.toHexString(signedTransaction)).send();
hashes.add(response.getTransactionHash());
}
// make sure that there are no more than one transaction per block, because the BLOCK_L1_SIZE
// limit only allows for one of these transactions.
assertTransactionsMinedInSeparateBlocks(web3j, hashes);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.junit.jupiter.api.Test;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;
public class TransactionTraceLimitOverflowLimitlessTest extends LineaPluginTestBase {
private static final BigInteger GAS_LIMIT = DefaultGasProvider.GAS_LIMIT;
private static final BigInteger VALUE = BigInteger.ZERO;
private static final BigInteger GAS_PRICE = BigInteger.TEN.pow(11);
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/strictModuleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.set("--plugin-linea-tx-pool-simulation-check-api-enabled=", "false")
.build();
}
@Test
public void transactionOverModuleLineCountRemoved() throws Exception {
final Web3j web3j = minerNode.nodeRequests().eth();
final String txData = Bytes.repeat((byte) 3, 2000).toUnprefixedHexString();
// this tx will not be selected since it goes above the max block size,
// but selection should go on and select the next one
final RawTransaction txModuleLineCountTooBig =
RawTransaction.createTransaction(
CHAIN_ID,
BigInteger.ZERO,
GAS_LIMIT.divide(BigInteger.TEN),
accounts.getPrimaryBenefactor().getAddress(),
VALUE,
txData,
GAS_PRICE,
GAS_PRICE.multiply(BigInteger.TEN).add(BigInteger.ONE));
final byte[] signedTxContractInteraction =
TransactionEncoder.signMessage(
txModuleLineCountTooBig, Credentials.create(Accounts.GENESIS_ACCOUNT_ONE_PRIVATE_KEY));
final EthSendTransaction signedTxContractInteractionResp =
web3j.ethSendRawTransaction(Numeric.toHexString(signedTxContractInteraction)).send();
// these are under the block size limit and should be selected
final Account fewLinesSender = accounts.getSecondaryBenefactor();
final Account recipient = accounts.createAccount("recipient");
final List<Hash> expectedConfirmedTxs = new ArrayList<>(4);
expectedConfirmedTxs.addAll(
minerNode.execute(
accountTransactions.createIncrementalTransfers(fewLinesSender, recipient, 4)));
expectedConfirmedTxs.stream()
.map(Hash::toHexString)
.forEach(hash -> minerNode.verify(eth.expectSuccessfulTransactionReceipt(hash)));
// assert that tx over line count limit is not confirmed and is removed from the pool
minerNode.verify(
eth.expectNoTransactionReceipt(signedTxContractInteractionResp.getTransactionHash()));
assertTransactionNotInThePool(signedTxContractInteractionResp.getTransactionHash());
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test.rpc.linea;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import linea.plugin.acc.test.LineaPluginTestBase;
import linea.plugin.acc.test.TestCommandLineOptionsBuilder;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import org.web3j.tx.gas.DefaultGasProvider;
public class EstimateGasModuleLimitOverflowLimitlessTest extends LineaPluginTestBase {
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/moduleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.build();
}
@Test
public void estimateGasFailsForExceedingModuleLineCountTest() throws Exception {
final var modExp = deployModExp();
final Bytes[] invalidInputs = {
Bytes.fromHexString("0000000000000000000000000000000000000000000000000000000000000201"),
Bytes.fromHexString("00000000000000000000000000000000000000000000000000000000000003"),
Bytes.fromHexString("ff"),
Bytes.fromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
};
for (int i = 0; i < invalidInputs.length; i++) {
final var modExpCalldata =
modExp.callModExp(invalidInputs[i].toArrayUnsafe()).encodeFunctionCall();
final EstimateGasTest.CallParams callParams =
new EstimateGasTest.CallParams(
null,
accounts.getSecondaryBenefactor().getAddress(),
null,
modExp.getContractAddress(),
null,
modExpCalldata,
"0",
DefaultGasProvider.GAS_PRICE.toString(),
null,
null);
final var reqLinea = new EstimateGasTest.BadLineaEstimateGasRequest(callParams);
final var respLinea = reqLinea.execute(minerNode.nodeRequests());
assertThat(respLinea.getCode()).isEqualTo(-32000);
assertThat(respLinea.getMessage())
.isEqualTo("Transaction line count for module MODEXP=2147483647 is above the limit 1");
}
}
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test.rpc.linea;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import linea.plugin.acc.test.LineaPluginTestBase;
import linea.plugin.acc.test.TestCommandLineOptionsBuilder;
import linea.plugin.acc.test.tests.web3j.generated.ExcludedPrecompiles;
import linea.plugin.acc.test.tests.web3j.generated.RevertExample;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.tests.acceptance.dsl.account.Account;
import org.hyperledger.besu.tests.acceptance.dsl.account.Accounts;
import org.hyperledger.besu.tests.acceptance.dsl.transaction.account.TransferTransactionSet;
import org.junit.jupiter.api.Test;
import org.web3j.abi.datatypes.generated.Bytes8;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;
public class EthSendRawTransactionSimulationCheckLimitlessTest extends LineaPluginTestBase {
private static final BigInteger GAS_LIMIT = DefaultGasProvider.GAS_LIMIT;
private static final BigInteger VALUE = BigInteger.ZERO;
private static final BigInteger GAS_PRICE = BigInteger.TEN.pow(9);
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/moduleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.set("--plugin-linea-tx-pool-simulation-check-api-enabled=", "true")
.build();
}
@Test
public void validTransactionsAreAccepted() {
// these are under the line count limit and should be accepted and selected
final Account recipient = accounts.createAccount("recipient");
final List<Hash> expectedConfirmedTxs = new ArrayList<>(4);
final var transfers =
IntStream.range(0, 4)
.mapToObj(
i ->
accountTransactions.createTransfer(
accounts.getSecondaryBenefactor(), recipient, i + 1, BigInteger.valueOf(i)))
.toList()
.reversed();
// reversed, so we are sure no tx is selected before all are sent due to the nonce gap,
// otherwise a block can be built with some txs before we can check the txpool content
expectedConfirmedTxs.addAll(minerNode.execute(new TransferTransactionSet(transfers)));
final var txPoolContentByHash = getTxPoolContent().stream().map(e -> e.get("hash")).toList();
assertThat(txPoolContentByHash)
.containsExactlyInAnyOrderElementsOf(
expectedConfirmedTxs.stream().map(Hash::toHexString).toList());
expectedConfirmedTxs.stream()
.map(Hash::toHexString)
.forEach(hash -> minerNode.verify(eth.expectSuccessfulTransactionReceipt(hash)));
}
@Test
public void transactionsThatRevertAreAccepted() throws Exception {
final RevertExample revertExample = deployRevertExample();
final Web3j web3j = minerNode.nodeRequests().eth();
final String contractAddress = revertExample.getContractAddress();
final String txData = revertExample.setValue(BigInteger.ZERO).encodeFunctionCall();
// this tx reverts but nevertheless it is accepted in the pool
final RawTransaction txThatReverts =
RawTransaction.createTransaction(
CHAIN_ID,
BigInteger.ZERO,
GAS_LIMIT.divide(BigInteger.TEN),
contractAddress,
VALUE,
txData,
GAS_PRICE,
GAS_PRICE.multiply(BigInteger.TEN).add(BigInteger.ONE));
final byte[] signedTxContractInteraction =
TransactionEncoder.signMessage(
txThatReverts, Credentials.create(Accounts.GENESIS_ACCOUNT_TWO_PRIVATE_KEY));
final EthSendTransaction signedTxContractInteractionResp =
web3j.ethSendRawTransaction(Numeric.toHexString(signedTxContractInteraction)).send();
assertThat(signedTxContractInteractionResp.hasError()).isFalse();
final var expectedConfirmedTxHash = signedTxContractInteractionResp.getTransactionHash();
minerNode.verify(eth.expectSuccessfulTransactionReceipt(expectedConfirmedTxHash));
}
@Test
public void transactionsWithExcludedPrecompilesAreNotAccepted() throws Exception {
final ExcludedPrecompiles excludedPrecompiles = deployExcludedPrecompiles();
final Web3j web3j = minerNode.nodeRequests().eth();
final String contractAddress = excludedPrecompiles.getContractAddress();
record InvalidCall(String encodedContractCall, String expectedErrorMessage) {}
final InvalidCall[] invalidCalls = {
new InvalidCall(
excludedPrecompiles
.callRIPEMD160("I am not allowed here".getBytes(StandardCharsets.UTF_8))
.encodeFunctionCall(),
"Transaction 0x35451c83b480b45df19105a30f22704df8750b7e328e1ebc646e6442f2f426f9 line count for module RIP=2147483647 is above the limit 1"),
new InvalidCall(
encodedCallBlake2F(excludedPrecompiles),
"Transaction 0xfd447b2b688f7448c875f68d9c85ffcb976e1cc722b70dae53e4f2e30d871be8 line count for module BLAKE=2147483647 is above the limit 1")
};
Arrays.stream(invalidCalls)
.forEach(
invalidCall -> {
// this tx must not be accepted
final RawTransaction txInvalid =
RawTransaction.createTransaction(
CHAIN_ID,
BigInteger.ZERO,
GAS_LIMIT.divide(BigInteger.TEN),
contractAddress,
VALUE,
invalidCall.encodedContractCall,
GAS_PRICE,
GAS_PRICE.multiply(BigInteger.TEN).add(BigInteger.ONE));
final byte[] signedTxInvalid =
TransactionEncoder.signMessage(
txInvalid, Credentials.create(Accounts.GENESIS_ACCOUNT_TWO_PRIVATE_KEY));
final EthSendTransaction signedTxContractInteractionResp;
try {
signedTxContractInteractionResp =
web3j.ethSendRawTransaction(Numeric.toHexString(signedTxInvalid)).send();
} catch (IOException e) {
throw new RuntimeException(e);
}
assertThat(signedTxContractInteractionResp.hasError()).isTrue();
assertThat(signedTxContractInteractionResp.getError().getMessage())
.isEqualTo(invalidCall.expectedErrorMessage);
});
assertThat(getTxPoolContent()).isEmpty();
}
private String encodedCallBlake2F(final ExcludedPrecompiles excludedPrecompiles) {
return excludedPrecompiles
.callBlake2f(
BigInteger.valueOf(12),
List.of(
Bytes32.fromHexString(
"0x48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5")
.toArrayUnsafe(),
Bytes32.fromHexString(
"0xd182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b")
.toArrayUnsafe()),
List.of(
Bytes32.fromHexString(
"0x6162630000000000000000000000000000000000000000000000000000000000")
.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe(),
Bytes32.ZERO.toArrayUnsafe()),
List.of(Bytes8.DEFAULT.getValue(), Bytes8.DEFAULT.getValue()),
true)
.encodeFunctionCall();
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright Consensys Software Inc.
*
* This file is dual-licensed under either the MIT license or Apache License 2.0.
* See the LICENSE-MIT and LICENSE-APACHE files in the repository root for details.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
package linea.plugin.acc.test.rpc.linea;
import static org.assertj.core.api.Assertions.assertThat;
import static org.web3j.crypto.Hash.sha3;
import java.util.List;
import linea.plugin.acc.test.LineaPluginTestBase;
import linea.plugin.acc.test.TestCommandLineOptionsBuilder;
import org.apache.tuweni.bytes.Bytes;
import org.junit.jupiter.api.Test;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.utils.Numeric;
public class EthSendRawTransactionSimulationModExpLimitlessTest extends LineaPluginTestBase {
@Override
public List<String> getTestCliOptions() {
return new TestCommandLineOptionsBuilder()
// set the module limits file
.set(
"--plugin-linea-module-limit-file-path=",
getResourcePath("/moduleLimitsLimitless.toml"))
// enabled the ZkCounter
.set("--plugin-linea-limitless-enabled=", "true")
.set("--plugin-linea-tx-pool-simulation-check-api-enabled=", "true")
.build();
}
@Test
public void validModExpCallsAreAccepted() throws Exception {
final var modExp = deployModExp();
final Bytes[] validInputs = {
Bytes.EMPTY,
Bytes.fromHexString("0000000000000000000000000000000000000000000000000000000000000000"),
Bytes.fromHexString("000000000000000000000000000000000000000000000000000000000000013f"),
Bytes.fromHexString("0000000000000000000000000000000000000000000000000000000000000200"),
Bytes.fromHexString("00000000000000000000000000000000000000000000000000000000000002")
};
for (int i = 0; i < validInputs.length; i++) {
final var mulmodOverflow =
encodedCallModExp(modExp, accounts.getSecondaryBenefactor(), i, validInputs[i]);
final Web3j web3j = minerNode.nodeRequests().eth();
final EthSendTransaction resp =
web3j.ethSendRawTransaction(Numeric.toHexString(mulmodOverflow)).send();
assertThat(resp.hasError()).isFalse();
minerNode.verify(eth.expectSuccessfulTransactionReceipt(resp.getTransactionHash()));
}
}
@Test
public void invalidModExpCallsAreRejected() throws Exception {
final var modExp = deployModExp();
final Bytes[] invalidInputs = {
Bytes.fromHexString("0000000000000000000000000000000000000000000000000000000000000201"),
Bytes.fromHexString("00000000000000000000000000000000000000000000000000000000000003"),
Bytes.fromHexString("ff"),
Bytes.fromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
};
for (int i = 0; i < invalidInputs.length; i++) {
final var mulmodOverflow =
encodedCallModExp(modExp, accounts.getSecondaryBenefactor(), i, invalidInputs[i]);
final Web3j web3j = minerNode.nodeRequests().eth();
final EthSendTransaction resp =
web3j.ethSendRawTransaction(Numeric.toHexString(mulmodOverflow)).send();
assertThat(resp.hasError()).isTrue();
assertThat(resp.getError().getMessage())
.isEqualTo(
"Transaction "
+ Numeric.toHexString(sha3(mulmodOverflow))
+ " line count for module MODEXP=2147483647 is above the limit 1");
assertThat(getTxPoolContent()).isEmpty();
}
}
}

View File

@@ -4,22 +4,61 @@
<Property name="root.log.level">TRACE</Property>
</Properties>
<Appenders>
<Console name="Console">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n" />
</Console>
<Memory name="Memory">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n" />
</Memory>
<Console name="Console">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n" />
</Console>
<Memory name="Memory">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSSZZZ} | %t | %-5level | %c{1} | %msg%n" />
</Memory>
<Console name="ConsoleBLC" target="SYSTEM_OUT">
<PatternLayout pattern='{"blockNumber":%X{blockNumber},"blockHash":"%X{blockHash}","traceCounts":{%X{traceCounts}}}%n'/>
</Console>
<Memory name="MemoryBLC">
<PatternLayout pattern='{"blockNumber":%X{blockNumber},"blockHash":"%X{blockHash}","traceCounts":{%X{traceCounts}}}%n'/>
</Memory>
<Console name="ConsoleITR" target="SYSTEM_OUT">
<PatternLayout pattern="Invalid tx removed:%X{txlog}, reason:%X{reason}; RLP={%X{txrlp}}}%n"/>
</Console>
<Memory name="MemoryITR">
<PatternLayout pattern="Invalid tx removed:%X{txlog}, reason:%X{reason}; RLP={%X{txrlp}}}%n"/>
</Memory>
<Async name="Main">
<AppenderRef ref="Console" />
<AppenderRef ref="Memory" />
</Async>
<Routing name="Router">
<Routes pattern="$${event:Marker}">
<Route key="BLOCK_LINE_COUNT">
<Async name="BLC">
<AppenderRef ref="ConsoleBLC" />
<AppenderRef ref="MemoryBLC" />
</Async>
</Route>
<Route key="INVALID_TX_REMOVED">
<Async name="ITR">
<AppenderRef ref="ConsoleITR" />
<AppenderRef ref="MemoryITR" />
</Async>
</Route>
<Route ref="Main" />
</Routes>
</Routing>
</Appenders>
<Loggers>
<Logger name="net.consensys.linea.sequencer.txselection.selectors.TraceLineLimitTransactionSelector" level="${sys:root.log.level}" additivity="false">
<AppenderRef ref="Router" />
</Logger>
<Logger name="org.hyperledger.besu.ethereum.eth.transactions" level="${sys:root.log.level}" additivity="false">
<AppenderRef ref="Router"/>
</Logger>
<Logger level="INFO" name="io.vertx" />
<Logger level="INFO" name="io.netty" />
<Logger level="INFO" name="org.web3j.protocol.http.HttpService" />
<Logger level="INFO" name="org.hyperledger.besu.ethereum.p2p.network.DefaultP2PNetwork" />
<Logger level="INFO" name="org.hyperledger.besu.ethereum.eth.manager.EthPeers" />
<Root level="${sys:root.log.level}">
<AppenderRef ref="Console" />
<AppenderRef ref="Memory" />
<AppenderRef ref="Main" />
</Root>
</Loggers>
</Configuration>

View File

@@ -0,0 +1,17 @@
##
# This file specifies prover limit by each EVM module
# WARN: The prover/arithmetization team has the owneship of this.
# Changing this values may compromise the system.
# issue: https://github.com/Consensys/zkevm-monorepo/issues/525
##
[traces-limits]
MODEXP = 1
RIP = 1
BLAKE = 1
#
# Block-specific limits
#
BLOCK_L1_SIZE = 1000000
BLOCK_L2_L1_LOGS = 16

View File

@@ -0,0 +1,17 @@
##
# This file specifies prover limit by each EVM module
# WARN: The prover/arithmetization team has the owneship of this.
# Changing this values may compromise the system.
# issue: https://github.com/Consensys/zkevm-monorepo/issues/525
##
[traces-limits]
MODEXP = 1
RIP = 1
BLAKE = 1
#
# Block-specific limits
#
BLOCK_L1_SIZE = 2000
BLOCK_L2_L1_LOGS = 16

View File

@@ -10,6 +10,7 @@ package net.consensys.linea.config;
import com.google.common.base.MoreObjects;
import net.consensys.linea.plugins.LineaCliOptions;
import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator;
import picocli.CommandLine;
public class LineaTracerCliOptions implements LineaCliOptions {
@@ -17,6 +18,8 @@ public class LineaTracerCliOptions implements LineaCliOptions {
public static final String MODULE_LIMIT_FILE_PATH = "--plugin-linea-module-limit-file-path";
public static final String DEFAULT_MODULE_LIMIT_FILE_PATH = "moduleLimitFile.toml";
public static final String LIMITLESS_ENABLED = "--plugin-linea-limitless-enabled";
public static final boolean DEFAULT_LIMITLESS_ENABLED = false;
@CommandLine.Option(
names = {MODULE_LIMIT_FILE_PATH},
@@ -26,6 +29,14 @@ public class LineaTracerCliOptions implements LineaCliOptions {
"Path to the toml file containing the module limits (default: ${DEFAULT-VALUE})")
private String moduleLimitFilePath = DEFAULT_MODULE_LIMIT_FILE_PATH;
@CommandLine.Option(
names = {LIMITLESS_ENABLED},
hidden = true,
paramLabel = "<BOOLEAN>",
description =
"If the sequencer needs to use or not the limitless prover (default: ${DEFAULT-VALUE})")
private boolean limitlessEnabled = DEFAULT_LIMITLESS_ENABLED;
private LineaTracerCliOptions() {}
/**
@@ -46,6 +57,7 @@ public class LineaTracerCliOptions implements LineaCliOptions {
public static LineaTracerCliOptions fromConfig(final LineaTracerConfiguration config) {
final LineaTracerCliOptions options = create();
options.moduleLimitFilePath = config.moduleLimitsFilePath();
options.limitlessEnabled = config.isLimitless();
return options;
}
@@ -56,13 +68,18 @@ public class LineaTracerCliOptions implements LineaCliOptions {
*/
@Override
public LineaTracerConfiguration toDomainObject() {
return LineaTracerConfiguration.builder().moduleLimitsFilePath(moduleLimitFilePath).build();
return LineaTracerConfiguration.builder()
.moduleLimitsFilePath(moduleLimitFilePath)
.moduleLimitsMap(ModuleLineCountValidator.createLimitModules(moduleLimitFilePath))
.isLimitless(limitlessEnabled)
.build();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add(MODULE_LIMIT_FILE_PATH, moduleLimitFilePath)
.add(LIMITLESS_ENABLED, limitlessEnabled)
.toString();
}
}

View File

@@ -9,10 +9,12 @@
package net.consensys.linea.config;
import java.util.Map;
import lombok.Builder;
import net.consensys.linea.plugins.LineaOptionsConfiguration;
/** The Linea tracer configuration. */
@Builder(toBuilder = true)
public record LineaTracerConfiguration(String moduleLimitsFilePath)
public record LineaTracerConfiguration(
String moduleLimitsFilePath, Map<String, Integer> moduleLimitsMap, boolean isLimitless)
implements LineaOptionsConfiguration {}

View File

@@ -19,17 +19,19 @@ import com.google.common.annotations.VisibleForTesting;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j;
import net.consensys.linea.bl.TransactionProfitabilityCalculator;
import net.consensys.linea.config.LineaProfitabilityConfiguration;
import net.consensys.linea.config.LineaRpcConfiguration;
import net.consensys.linea.config.LineaTracerConfiguration;
import net.consensys.linea.config.LineaTransactionPoolValidatorConfiguration;
import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration;
import net.consensys.linea.sequencer.modulelimit.ModuleLimitsValidationResult;
import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator;
import net.consensys.linea.zktracer.LineCountingTracer;
import net.consensys.linea.zktracer.ZkCounter;
import net.consensys.linea.zktracer.ZkTracer;
import org.apache.tuweni.bytes.Bytes;
import org.bouncycastle.asn1.sec.SECNamedCurves;
@@ -86,6 +88,7 @@ public class LineaEstimateGas {
private LineaProfitabilityConfiguration profitabilityConf;
private TransactionProfitabilityCalculator txProfitabilityCalculator;
private LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration;
private LineaTracerConfiguration tracerConfiguration;
private ModuleLineCountValidator moduleLineCountValidator;
public LineaEstimateGas(
@@ -103,14 +106,16 @@ public class LineaEstimateGas {
final LineaRpcConfiguration rpcConfiguration,
final LineaTransactionPoolValidatorConfiguration transactionValidatorConfiguration,
final LineaProfitabilityConfiguration profitabilityConf,
final Map<String, Integer> limitsMap,
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration) {
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration,
final LineaTracerConfiguration tracerConfiguration) {
this.rpcConfiguration = rpcConfiguration;
this.txValidatorConf = transactionValidatorConfiguration;
this.profitabilityConf = profitabilityConf;
this.txProfitabilityCalculator = new TransactionProfitabilityCalculator(profitabilityConf);
this.l1L2BridgeConfiguration = l1L2BridgeConfiguration;
this.moduleLineCountValidator = new ModuleLineCountValidator(limitsMap);
this.tracerConfiguration = tracerConfiguration;
this.moduleLineCountValidator =
new ModuleLineCountValidator(tracerConfiguration.moduleLimitsMap());
}
public String getNamespace() {
@@ -230,14 +235,15 @@ public class LineaEstimateGas {
final long logId) {
final var pendingBlockHeader = transactionSimulationService.simulatePendingBlockHeader();
final var zkTracer = createZkTracer(pendingBlockHeader, blockchainService.getChainId().get());
final var lineCountingTracer =
createLineCountingTracer(pendingBlockHeader, blockchainService.getChainId().get());
final var maybeSimulationResults =
transactionSimulationService.simulate(
transaction, maybeStateOverrides, pendingBlockHeader, zkTracer, false, true);
transaction, maybeStateOverrides, pendingBlockHeader, lineCountingTracer, false, true);
ModuleLimitsValidationResult moduleLimit =
moduleLineCountValidator.validate(zkTracer.getModulesLineCount());
moduleLineCountValidator.validate(lineCountingTracer.getModulesLineCount());
if (moduleLimit.getResult() != ModuleLineCountValidator.ModuleLineCountResult.VALID) {
handleModuleOverLimit(moduleLimit);
@@ -395,12 +401,15 @@ public class LineaEstimateGas {
.orElse(0L);
}
private ZkTracer createZkTracer(
private LineCountingTracer createLineCountingTracer(
final ProcessableBlockHeader pendingBlockHeader, final BigInteger chainId) {
var zkTracer = new ZkTracer(LONDON, l1L2BridgeConfiguration, chainId);
zkTracer.traceStartConflation(1L);
zkTracer.traceStartBlock(pendingBlockHeader, pendingBlockHeader.getCoinbase());
return zkTracer;
final var lineCountingTracer =
tracerConfiguration.isLimitless()
? new ZkCounter(l1L2BridgeConfiguration)
: new ZkTracer(LONDON, l1L2BridgeConfiguration, chainId);
lineCountingTracer.traceStartConflation(1L);
lineCountingTracer.traceStartBlock(pendingBlockHeader, pendingBlockHeader.getCoinbase());
return lineCountingTracer;
}
private void handleModuleOverLimit(ModuleLimitsValidationResult moduleLimitResult) {

View File

@@ -9,8 +9,6 @@
package net.consensys.linea.rpc.services;
import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.createLimitModules;
import com.google.auto.service.AutoService;
import lombok.extern.slf4j.Slf4j;
import net.consensys.linea.AbstractLineaRequiredPlugin;
@@ -60,8 +58,8 @@ public class LineaEstimateGasEndpointPlugin extends AbstractLineaRequiredPlugin
lineaRpcConfiguration(),
transactionPoolValidatorConfiguration(),
profitabilityConfiguration(),
createLimitModules(tracerConfiguration()),
l1L2BridgeSharedConfiguration());
l1L2BridgeSharedConfiguration(),
tracerConfiguration());
}
@Override

View File

@@ -16,7 +16,6 @@ import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import net.consensys.linea.config.LineaTracerConfiguration;
import org.apache.tuweni.toml.Toml;
import org.apache.tuweni.toml.TomlParseResult;
import org.apache.tuweni.toml.TomlTable;
@@ -118,10 +117,9 @@ public class ModuleLineCountValidator {
INVALID_LINE_COUNT
}
public static Map<String, Integer> createLimitModules(
LineaTracerConfiguration lineaTracerConfiguration) {
public static Map<String, Integer> createLimitModules(String moduleLimitsFilePath) {
try {
URL url = new File(lineaTracerConfiguration.moduleLimitsFilePath()).toURI().toURL();
URL url = new File(moduleLimitsFilePath).toURI().toURL();
final String tomlString = Resources.toString(url, StandardCharsets.UTF_8);
TomlParseResult result = Toml.parse(tomlString);
final TomlTable table = result.getTable("traces-limits");
@@ -135,7 +133,7 @@ public class ModuleLineCountValidator {
} catch (final Exception e) {
final String errorMsg =
"Problem reading the toml file containing the limits for the modules: "
+ lineaTracerConfiguration.moduleLimitsFilePath();
+ moduleLimitsFilePath;
log.error(errorMsg);
throw new RuntimeException(errorMsg, e);
}

View File

@@ -10,10 +10,10 @@
package net.consensys.linea.sequencer.txpoolvalidation;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import net.consensys.linea.config.LineaProfitabilityConfiguration;
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;
@@ -38,8 +38,8 @@ public class LineaTransactionPoolValidatorFactory implements PluginTransactionPo
private final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf;
private final LineaProfitabilityConfiguration profitabilityConf;
private final Set<Address> denied;
private final Map<String, Integer> moduleLineLimitsMap;
private final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration;
private final LineaTracerConfiguration tracerConfiguration;
private final Optional<JsonRpcManager> rejectedTxJsonRpcManager;
public LineaTransactionPoolValidatorFactory(
@@ -49,7 +49,7 @@ public class LineaTransactionPoolValidatorFactory implements PluginTransactionPo
final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf,
final LineaProfitabilityConfiguration profitabilityConf,
final Set<Address> deniedAddresses,
final Map<String, Integer> moduleLineLimitsMap,
final LineaTracerConfiguration tracerConfiguration,
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration,
final Optional<JsonRpcManager> rejectedTxJsonRpcManager) {
this.besuConfiguration = besuConfiguration;
@@ -58,7 +58,7 @@ public class LineaTransactionPoolValidatorFactory implements PluginTransactionPo
this.txPoolValidatorConf = txPoolValidatorConf;
this.profitabilityConf = profitabilityConf;
this.denied = deniedAddresses;
this.moduleLineLimitsMap = moduleLineLimitsMap;
this.tracerConfiguration = tracerConfiguration;
this.l1L2BridgeConfiguration = l1L2BridgeConfiguration;
this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager;
}
@@ -81,7 +81,7 @@ public class LineaTransactionPoolValidatorFactory implements PluginTransactionPo
blockchainService,
transactionSimulationService,
txPoolValidatorConf,
moduleLineLimitsMap,
tracerConfiguration,
l1L2BridgeConfiguration,
rejectedTxJsonRpcManager)
};

View File

@@ -10,7 +10,6 @@
package net.consensys.linea.sequencer.txpoolvalidation;
import static net.consensys.linea.metrics.LineaMetricCategory.TX_POOL_PROFITABILITY;
import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.createLimitModules;
import com.google.auto.service.AutoService;
import java.io.File;
@@ -104,7 +103,7 @@ public class LineaTransactionPoolValidatorPlugin extends AbstractLineaRequiredPl
transactionPoolValidatorConfiguration(),
profitabilityConfiguration(),
deniedAddresses,
createLimitModules(tracerConfiguration()),
tracerConfiguration(),
l1L2BridgeSharedConfiguration(),
rejectedTxJsonRpcManager));

View File

@@ -15,15 +15,17 @@ import static net.consensys.linea.zktracer.Fork.LONDON;
import java.math.BigInteger;
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.LineaTracerConfiguration;
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;
import net.consensys.linea.zktracer.LineCountingTracer;
import net.consensys.linea.zktracer.ZkCounter;
import net.consensys.linea.zktracer.ZkTracer;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
@@ -41,22 +43,22 @@ public class SimulationValidator implements PluginTransactionPoolValidator {
private final BlockchainService blockchainService;
private final TransactionSimulationService transactionSimulationService;
private final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf;
private final Map<String, Integer> moduleLineLimitsMap;
private final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration;
private final LineaTracerConfiguration tracerConfiguration;
private final Optional<JsonRpcManager> rejectedTxJsonRpcManager;
public SimulationValidator(
final BlockchainService blockchainService,
final TransactionSimulationService transactionSimulationService,
final LineaTransactionPoolValidatorConfiguration txPoolValidatorConf,
final Map<String, Integer> moduleLineLimitsMap,
final LineaTracerConfiguration tracerConfiguration,
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration,
final Optional<JsonRpcManager> rejectedTxJsonRpcManager) {
this.blockchainService = blockchainService;
this.transactionSimulationService = transactionSimulationService;
this.txPoolValidatorConf = txPoolValidatorConf;
this.moduleLineLimitsMap = moduleLineLimitsMap;
this.l1L2BridgeConfiguration = l1L2BridgeConfiguration;
this.tracerConfiguration = tracerConfiguration;
this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager;
}
@@ -78,16 +80,17 @@ public class SimulationValidator implements PluginTransactionPoolValidator {
.log();
final ModuleLineCountValidator moduleLineCountValidator =
new ModuleLineCountValidator(moduleLineLimitsMap);
new ModuleLineCountValidator(tracerConfiguration.moduleLimitsMap());
final var pendingBlockHeader = transactionSimulationService.simulatePendingBlockHeader();
final var zkTracer = createZkTracer(pendingBlockHeader, blockchainService.getChainId().get());
final var lineCountingTracer =
createLineCountingTracer(pendingBlockHeader, blockchainService.getChainId().get());
final var maybeSimulationResults =
transactionSimulationService.simulate(
transaction, Optional.empty(), pendingBlockHeader, zkTracer, false, true);
transaction, Optional.empty(), pendingBlockHeader, lineCountingTracer, false, true);
ModuleLimitsValidationResult moduleLimitResult =
moduleLineCountValidator.validate(zkTracer.getModulesLineCount());
moduleLineCountValidator.validate(lineCountingTracer.getModulesLineCount());
logSimulationResult(
transaction, isLocal, hasPriority, maybeSimulationResults, moduleLimitResult);
@@ -153,12 +156,15 @@ public class SimulationValidator implements PluginTransactionPoolValidator {
.log();
}
private ZkTracer createZkTracer(
private LineCountingTracer createLineCountingTracer(
final ProcessableBlockHeader pendingBlockHeader, BigInteger chainId) {
var zkTracer = new ZkTracer(LONDON, l1L2BridgeConfiguration, chainId);
zkTracer.traceStartConflation(1L);
zkTracer.traceStartBlock(pendingBlockHeader, pendingBlockHeader.getCoinbase());
return zkTracer;
var lineCountingTracer =
tracerConfiguration.isLimitless()
? new ZkCounter(l1L2BridgeConfiguration)
: new ZkTracer(LONDON, l1L2BridgeConfiguration, chainId);
lineCountingTracer.traceStartConflation(1L);
lineCountingTracer.traceStartBlock(pendingBlockHeader, pendingBlockHeader.getCoinbase());
return lineCountingTracer;
}
private String handleModuleOverLimit(

View File

@@ -9,7 +9,6 @@
package net.consensys.linea.sequencer.txselection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
@@ -44,7 +43,6 @@ public class LineaTransactionSelectorFactory implements PluginTransactionSelecto
private final LineaTracerConfiguration tracerConfiguration;
private final Optional<HistogramMetrics> maybeProfitabilityMetrics;
private final BundlePoolService bundlePoolService;
private final Map<String, Integer> limitsMap;
private final AtomicReference<LineaTransactionSelector> currSelector = new AtomicReference<>();
public LineaTransactionSelectorFactory(
@@ -53,7 +51,6 @@ public class LineaTransactionSelectorFactory implements PluginTransactionSelecto
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration,
final LineaProfitabilityConfiguration profitabilityConfiguration,
final LineaTracerConfiguration tracerConfiguration,
final Map<String, Integer> limitsMap,
final Optional<JsonRpcManager> rejectedTxJsonRpcManager,
final Optional<HistogramMetrics> maybeProfitabilityMetrics,
final BundlePoolService bundlePoolService) {
@@ -62,7 +59,6 @@ public class LineaTransactionSelectorFactory implements PluginTransactionSelecto
this.l1L2BridgeConfiguration = l1L2BridgeConfiguration;
this.profitabilityConfiguration = profitabilityConfiguration;
this.tracerConfiguration = tracerConfiguration;
this.limitsMap = limitsMap;
this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager;
this.maybeProfitabilityMetrics = maybeProfitabilityMetrics;
this.bundlePoolService = bundlePoolService;
@@ -79,7 +75,6 @@ public class LineaTransactionSelectorFactory implements PluginTransactionSelecto
profitabilityConfiguration,
tracerConfiguration,
bundlePoolService,
limitsMap,
rejectedTxJsonRpcManager,
maybeProfitabilityMetrics);
currSelector.set(selector);

View File

@@ -10,7 +10,6 @@
package net.consensys.linea.sequencer.txselection;
import static net.consensys.linea.metrics.LineaMetricCategory.SEQUENCER_PROFITABILITY;
import static net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator.createLimitModules;
import com.google.auto.service.AutoService;
import java.util.Optional;
@@ -90,7 +89,6 @@ public class LineaTransactionSelectorPlugin extends AbstractLineaRequiredPlugin
l1L2BridgeSharedConfiguration(),
profitabilityConfiguration(),
tracerConfiguration(),
createLimitModules(tracerConfiguration()),
rejectedTxJsonRpcManager,
maybeProfitabilityMetrics,
bundlePoolService));

View File

@@ -14,7 +14,6 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectio
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
@@ -27,7 +26,7 @@ import net.consensys.linea.jsonrpc.JsonRpcManager;
import net.consensys.linea.jsonrpc.JsonRpcRequestBuilder;
import net.consensys.linea.metrics.HistogramMetrics;
import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration;
import net.consensys.linea.zktracer.ZkTracer;
import net.consensys.linea.zktracer.LineCountingTracer;
import org.hyperledger.besu.plugin.data.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.services.BlockchainService;
@@ -52,7 +51,6 @@ public class LineaTransactionSelector implements PluginTransactionSelector {
final LineaProfitabilityConfiguration profitabilityConfiguration,
final LineaTracerConfiguration tracerConfiguration,
final BundlePoolService bundlePoolService,
final Map<String, Integer> limitsMap,
final Optional<JsonRpcManager> rejectedTxJsonRpcManager,
final Optional<HistogramMetrics> maybeProfitabilityMetrics) {
this.rejectedTxJsonRpcManager = rejectedTxJsonRpcManager;
@@ -72,7 +70,6 @@ public class LineaTransactionSelector implements PluginTransactionSelector {
profitabilityConfiguration,
tracerConfiguration,
bundlePoolService,
limitsMap,
maybeProfitabilityMetrics);
}
@@ -97,14 +94,12 @@ public class LineaTransactionSelector implements PluginTransactionSelector {
final LineaProfitabilityConfiguration profitabilityConfiguration,
final LineaTracerConfiguration tracerConfiguration,
final BundlePoolService bundlePoolService,
final Map<String, Integer> limitsMap,
final Optional<HistogramMetrics> maybeProfitabilityMetrics) {
traceLineLimitTransactionSelector =
new TraceLineLimitTransactionSelector(
selectorsStateManager,
blockchainService.getChainId().get(),
limitsMap,
txSelectorConfiguration,
l1L2BridgeConfiguration,
tracerConfiguration);
@@ -229,7 +224,7 @@ public class LineaTransactionSelector implements PluginTransactionSelector {
* @return the operation tracer
*/
@Override
public ZkTracer getOperationTracer() {
public LineCountingTracer getOperationTracer() {
return traceLineLimitTransactionSelector.getOperationTracer();
}
}

View File

@@ -12,13 +12,14 @@ import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectio
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_MODULE_LINE_COUNT_OVERFLOW;
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_MODULE_LINE_COUNT_OVERFLOW_CACHED;
import static net.consensys.linea.sequencer.txselection.LineaTransactionSelectionResult.TX_MODULE_LINE_INVALID_COUNT;
import static net.consensys.linea.zktracer.Fork.LONDON;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import com.google.common.annotations.VisibleForTesting;
import java.math.BigInteger;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -28,12 +29,24 @@ import net.consensys.linea.config.LineaTransactionSelectorConfiguration;
import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration;
import net.consensys.linea.sequencer.modulelimit.ModuleLimitsValidationResult;
import net.consensys.linea.sequencer.modulelimit.ModuleLineCountValidator;
import net.consensys.linea.zktracer.Fork;
import net.consensys.linea.zktracer.LineCountingTracer;
import net.consensys.linea.zktracer.ZkCounter;
import net.consensys.linea.zktracer.ZkTracer;
import net.consensys.linea.zktracer.container.module.Module;
import org.apache.tuweni.bytes.Bytes;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.worldstate.WorldView;
import org.hyperledger.besu.plugin.data.BlockBody;
import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
import org.hyperledger.besu.plugin.data.TransactionProcessingResult;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.services.txselection.AbstractStatefulPluginTransactionSelector;
@@ -52,39 +65,39 @@ public class TraceLineLimitTransactionSelector
extends AbstractStatefulPluginTransactionSelector<Map<String, Integer>> {
private static final Marker BLOCK_LINE_COUNT_MARKER = MarkerFactory.getMarker("BLOCK_LINE_COUNT");
@VisibleForTesting protected static Set<Hash> overLineCountLimitCache = new LinkedHashSet<>();
private final ZkTracer zkTracer;
private final LineaTracerConfiguration tracerConfiguration;
private final LineCountingTracer lineCountingTracer;
private final BigInteger chainId;
private final String limitFilePath;
private final Map<String, Integer> moduleLimits;
private final int overLimitCacheSize;
private final ModuleLineCountValidator moduleLineCountValidator;
public TraceLineLimitTransactionSelector(
final SelectorsStateManager stateManager,
final BigInteger chainId,
final Map<String, Integer> moduleLimits,
final LineaTransactionSelectorConfiguration txSelectorConfiguration,
final LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration,
final LineaTracerConfiguration tracerConfiguration) {
super(
stateManager,
moduleLimits.keySet().stream().collect(Collectors.toMap(Function.identity(), unused -> 0)),
tracerConfiguration.moduleLimitsMap().keySet().stream()
.collect(Collectors.toMap(Function.identity(), unused -> 0)),
Map::copyOf);
this.chainId = chainId;
this.moduleLimits = moduleLimits;
this.limitFilePath = tracerConfiguration.moduleLimitsFilePath();
this.tracerConfiguration = tracerConfiguration;
this.overLimitCacheSize = txSelectorConfiguration.overLinesLimitCacheSize();
zkTracer = new ZkTracerWithLog(l1L2BridgeConfiguration);
for (Module m : zkTracer.getHub().getModulesToCount()) {
if (!moduleLimits.containsKey(m.moduleKey())) {
lineCountingTracer =
new LineCountingTracerWithLog(tracerConfiguration, l1L2BridgeConfiguration);
for (Module m : lineCountingTracer.getModulesToCount()) {
if (!tracerConfiguration.moduleLimitsMap().containsKey(m.moduleKey())) {
throw new IllegalStateException(
"Limit for module %s not defined in %s".formatted(m.moduleKey(), this.limitFilePath));
"Limit for module %s not defined in %s"
.formatted(m.moduleKey(), tracerConfiguration.moduleLimitsFilePath()));
}
}
zkTracer.traceStartConflation(1L);
moduleLineCountValidator = new ModuleLineCountValidator(moduleLimits);
lineCountingTracer.traceStartConflation(1L);
moduleLineCountValidator = new ModuleLineCountValidator(tracerConfiguration.moduleLimitsMap());
}
/**
@@ -125,7 +138,7 @@ public class TraceLineLimitTransactionSelector
final var prevCumulatedLineCountMap = getWorkingState();
// check that we are not exceeding line number for any module
final var newCumulatedLineCountMap = zkTracer.getModulesLineCount();
final var newCumulatedLineCountMap = lineCountingTracer.getModulesLineCount();
final Transaction transaction = evaluationContext.getPendingTransaction().getTransaction();
log.atTrace()
.setMessage("Tx {} line count per module: {}")
@@ -176,8 +189,8 @@ public class TraceLineLimitTransactionSelector
}
@Override
public ZkTracer getOperationTracer() {
return zkTracer;
public LineCountingTracer getOperationTracer() {
return lineCountingTracer;
}
private void rememberOverLineCountLimitTransaction(final Transaction transaction) {
@@ -208,18 +221,25 @@ public class TraceLineLimitTransactionSelector
+ "/"
+ e.getValue()
+ "/"
+ moduleLimits.get(e.getKey()))
+ tracerConfiguration.moduleLimitsMap().get(e.getKey()))
.collect(Collectors.joining(",", "[", "]"));
}
private class ZkTracerWithLog extends ZkTracer {
public ZkTracerWithLog(final LineaL1L2BridgeSharedConfiguration bridgeConfiguration) {
super(LONDON, bridgeConfiguration, chainId);
private class LineCountingTracerWithLog implements LineCountingTracer {
private final LineCountingTracer delegate;
public LineCountingTracerWithLog(
final LineaTracerConfiguration tracerConfiguration,
final LineaL1L2BridgeSharedConfiguration bridgeConfiguration) {
this.delegate =
tracerConfiguration.isLimitless()
? new ZkCounter(bridgeConfiguration)
: new ZkTracer(Fork.LONDON, bridgeConfiguration, chainId);
}
@Override
public void traceEndBlock(final BlockHeader blockHeader, final BlockBody blockBody) {
super.traceEndBlock(blockHeader, blockBody);
delegate.traceEndBlock(blockHeader, blockBody);
log.atDebug()
.addMarker(BLOCK_LINE_COUNT_MARKER)
.addKeyValue("blockNumber", blockHeader::getNumber)
@@ -233,5 +253,120 @@ public class TraceLineLimitTransactionSelector
.collect(Collectors.joining(",")))
.log();
}
@Override
public void popTransactionBundle() {
delegate.popTransactionBundle();
}
@Override
public void commitTransactionBundle() {
delegate.commitTransactionBundle();
}
@Override
public Map<String, Integer> getModulesLineCount() {
return delegate.getModulesLineCount();
}
@Override
public List<Module> getModulesToCount() {
return delegate.getModulesToCount();
}
@Override
public void traceStartConflation(final long l) {
delegate.traceStartConflation(l);
}
@Override
public void traceEndConflation(final WorldView worldView) {
delegate.traceEndConflation(worldView);
}
@Override
public void traceStartBlock(
final BlockHeader blockHeader, final BlockBody blockBody, final Address miningBeneficiary) {
delegate.traceStartBlock(blockHeader, blockBody, miningBeneficiary);
}
@Override
public void traceStartBlock(
final ProcessableBlockHeader processableBlockHeader, final Address miningBeneficiary) {
delegate.traceStartBlock(processableBlockHeader, miningBeneficiary);
}
@Override
public boolean isExtendedTracing() {
return delegate.isExtendedTracing();
}
@Override
public void tracePreExecution(final MessageFrame frame) {
delegate.tracePreExecution(frame);
}
@Override
public void tracePostExecution(
final MessageFrame frame, final Operation.OperationResult operationResult) {
delegate.tracePostExecution(frame, operationResult);
}
@Override
public void tracePrecompileCall(
final MessageFrame frame, final long gasRequirement, final Bytes output) {
delegate.tracePrecompileCall(frame, gasRequirement, output);
}
@Override
public void traceAccountCreationResult(
final MessageFrame frame, final Optional<ExceptionalHaltReason> haltReason) {
delegate.traceAccountCreationResult(frame, haltReason);
}
@Override
public void tracePrepareTransaction(final WorldView worldView, final Transaction transaction) {
delegate.tracePrepareTransaction(worldView, transaction);
}
@Override
public void traceStartTransaction(final WorldView worldView, final Transaction transaction) {
delegate.traceStartTransaction(worldView, transaction);
}
@Override
public void traceBeforeRewardTransaction(
final WorldView worldView, final Transaction tx, final Wei miningReward) {
delegate.traceBeforeRewardTransaction(worldView, tx, miningReward);
}
@Override
public void traceEndTransaction(
final WorldView worldView,
final Transaction tx,
final boolean status,
final Bytes output,
final List<Log> logs,
final long gasUsed,
final Set<Address> selfDestructs,
final long timeNs) {
delegate.traceEndTransaction(
worldView, tx, status, output, logs, gasUsed, selfDestructs, timeNs);
}
@Override
public void traceContextEnter(final MessageFrame frame) {
delegate.traceContextEnter(frame);
}
@Override
public void traceContextReEnter(final MessageFrame frame) {
delegate.traceContextReEnter(frame);
}
@Override
public void traceContextExit(final MessageFrame frame) {
delegate.traceContextExit(frame);
}
}
}

View File

@@ -33,7 +33,6 @@ 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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -96,11 +95,10 @@ public class SimulationValidatorTest {
curve.getN());
}
private Map<String, Integer> lineCountLimits;
@Mock BlockchainService blockchainService;
@Mock TransactionSimulationService transactionSimulationService;
private JsonRpcManager jsonRpcManager;
private LineaTracerConfiguration tracerConfiguration;
@TempDir private Path tempDataDir;
@TempDir static Path tempDir;
static Path lineLimitsConfPath;
@@ -116,11 +114,14 @@ public class SimulationValidatorTest {
@BeforeEach
public void initialize(final WireMockRuntimeInfo wmInfo) throws MalformedURLException {
final var tracerConf =
tracerConfiguration =
LineaTracerConfiguration.builder()
.moduleLimitsFilePath(lineLimitsConfPath.toString())
.moduleLimitsMap(
new HashMap<>(
ModuleLineCountValidator.createLimitModules(lineLimitsConfPath.toString())))
.isLimitless(false)
.build();
lineCountLimits = new HashMap<>(ModuleLineCountValidator.createLimitModules(tracerConf));
final var pendingBlockHeader = mock(BlockHeader.class);
when(pendingBlockHeader.getBaseFee()).thenReturn(Optional.of(BASE_FEE));
when(pendingBlockHeader.getCoinbase()).thenReturn(Address.ZERO);
@@ -152,9 +153,7 @@ public class SimulationValidatorTest {
}
private SimulationValidator createSimulationValidator(
final Map<String, Integer> lineCountLimits,
final boolean enableForApi,
final boolean enableForP2p) {
final boolean enableForApi, final boolean enableForP2p) {
return new SimulationValidator(
blockchainService,
transactionSimulationService,
@@ -162,7 +161,7 @@ public class SimulationValidatorTest {
.txPoolSimulationCheckApiEnabled(enableForApi)
.txPoolSimulationCheckP2pEnabled(enableForP2p)
.build(),
lineCountLimits,
tracerConfiguration,
LineaL1L2BridgeSharedConfiguration.builder()
.contract(BRIDGE_CONTRACT)
.topic(BRIDGE_LOG_TOPIC)
@@ -172,7 +171,7 @@ public class SimulationValidatorTest {
@Test
public void successfulTransactionIsValid() {
final var simulationValidator = createSimulationValidator(lineCountLimits, true, false);
final var simulationValidator = createSimulationValidator(true, false);
final org.hyperledger.besu.ethereum.core.Transaction transaction =
org.hyperledger.besu.ethereum.core.Transaction.builder()
.sender(SENDER)
@@ -188,8 +187,8 @@ public class SimulationValidatorTest {
@Test
public void moduleLineCountOverflowTransactionIsInvalidAndReported() {
lineCountLimits.put("EXT", 5);
final var simulationValidator = createSimulationValidator(lineCountLimits, true, false);
tracerConfiguration.moduleLimitsMap().put("EXT", 5);
final var simulationValidator = createSimulationValidator(true, false);
final org.hyperledger.besu.ethereum.core.Transaction transaction =
org.hyperledger.besu.ethereum.core.Transaction.builder()
.sender(SENDER)

View File

@@ -22,7 +22,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import net.consensys.linea.bundles.BundlePoolService;
@@ -67,7 +66,6 @@ class LineaTransactionSelectorFactoryTest {
private LineaTransactionSelectorConfiguration mockTxSelectorConfiguration;
private LineaL1L2BridgeSharedConfiguration l1L2BridgeConfiguration;
private LineaProfitabilityConfiguration mockProfitabilityConfiguration;
private Map<String, Integer> lineCountLimits;
private BesuEvents mockEvents;
private LineaLimitedBundlePool bundlePool;
private BundlePoolService mockBundlePool;
@@ -92,9 +90,11 @@ class LineaTransactionSelectorFactoryTest {
lineaTracerConfiguration =
LineaTracerConfiguration.builder()
.moduleLimitsFilePath(lineLimitsConfPath.toString())
.moduleLimitsMap(
new HashMap<>(
ModuleLineCountValidator.createLimitModules(lineLimitsConfPath.toString())))
.isLimitless(false)
.build();
lineCountLimits =
new HashMap<>(ModuleLineCountValidator.createLimitModules(lineaTracerConfiguration));
mockBlockchainService = mock(BlockchainService.class);
when(mockBlockchainService.getChainId()).thenReturn(Optional.of(BigInteger.ONE));
@@ -113,7 +113,6 @@ class LineaTransactionSelectorFactoryTest {
l1L2BridgeConfiguration,
mockProfitabilityConfiguration,
lineaTracerConfiguration,
lineCountLimits,
Optional.empty(),
Optional.empty(),
bundlePool);

View File

@@ -20,7 +20,6 @@ import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import net.consensys.linea.config.LineaTracerConfiguration;
import net.consensys.linea.config.LineaTransactionSelectorConfiguration;
import net.consensys.linea.plugins.config.LineaL1L2BridgeSharedConfiguration;
@@ -45,8 +44,7 @@ import org.junit.jupiter.api.io.TempDir;
public class TraceLineLimitTransactionSelectorTest {
private static final int OVER_LINE_COUNT_LIMIT_CACHE_SIZE = 2;
private static final String MODULE_LINE_LIMITS_RESOURCE_NAME = "/sequencer/line-limits.toml";
private Map<String, Integer> lineCountLimits;
private LineaTracerConfiguration lineaTracerConfiguration;
private LineaTracerConfiguration tracerConfiguration;
private SelectorsStateManager selectorsStateManager;
@TempDir static Path tempDir;
@@ -63,30 +61,27 @@ public class TraceLineLimitTransactionSelectorTest {
@BeforeEach
public void initialize() {
lineaTracerConfiguration =
tracerConfiguration =
LineaTracerConfiguration.builder()
.moduleLimitsFilePath(lineLimitsConfPath.toString())
.moduleLimitsMap(
new HashMap<>(
ModuleLineCountValidator.createLimitModules(lineLimitsConfPath.toString())))
.build();
lineCountLimits =
new HashMap<>(ModuleLineCountValidator.createLimitModules(lineaTracerConfiguration));
}
private TestableTraceLineLimitTransactionSelector newSelectorForNewBlock(
final Map<String, Integer> lineCountLimits) {
private TestableTraceLineLimitTransactionSelector newSelectorForNewBlock() {
selectorsStateManager = new SelectorsStateManager();
final var selector =
new TestableTraceLineLimitTransactionSelector(
selectorsStateManager,
lineaTracerConfiguration,
lineCountLimits,
OVER_LINE_COUNT_LIMIT_CACHE_SIZE);
selectorsStateManager, tracerConfiguration, OVER_LINE_COUNT_LIMIT_CACHE_SIZE);
selectorsStateManager.blockSelectionStarted();
return selector;
}
@Test
public void shouldSelectWhenBelowLimits() {
final var transactionSelector = newSelectorForNewBlock(lineCountLimits);
final var transactionSelector = newSelectorForNewBlock();
transactionSelector.resetCache();
final var evaluationContext =
@@ -105,8 +100,8 @@ public class TraceLineLimitTransactionSelectorTest {
@Test
public void shouldNotSelectWhenOverLimits() {
lineCountLimits.put("EXT", 5);
final var transactionSelector = newSelectorForNewBlock(lineCountLimits);
tracerConfiguration.moduleLimitsMap().put("EXT", 5);
final var transactionSelector = newSelectorForNewBlock();
transactionSelector.resetCache();
final var evaluationContext =
@@ -125,8 +120,8 @@ public class TraceLineLimitTransactionSelectorTest {
@Test
public void shouldNotReprocessedWhenOverLimits() {
lineCountLimits.put("EXT", 5);
var transactionSelector = newSelectorForNewBlock(lineCountLimits);
tracerConfiguration.moduleLimitsMap().put("EXT", 5);
var transactionSelector = newSelectorForNewBlock();
transactionSelector.resetCache();
var evaluationContext =
@@ -142,7 +137,7 @@ public class TraceLineLimitTransactionSelectorTest {
transactionSelector.isOverLineCountLimitTxCached(
evaluationContext.getPendingTransaction().getTransaction().getHash()))
.isTrue();
transactionSelector = newSelectorForNewBlock(lineCountLimits);
transactionSelector = newSelectorForNewBlock();
assertThat(
transactionSelector.isOverLineCountLimitTxCached(
evaluationContext.getPendingTransaction().getTransaction().getHash()))
@@ -162,8 +157,8 @@ public class TraceLineLimitTransactionSelectorTest {
@Test
public void shouldEvictWhenCacheIsFull() {
lineCountLimits.put("EXT", 5);
final var transactionSelector = newSelectorForNewBlock(lineCountLimits);
tracerConfiguration.moduleLimitsMap().put("EXT", 5);
final var transactionSelector = newSelectorForNewBlock();
transactionSelector.resetCache();
final TestTransactionEvaluationContext[] evaluationContexts =
@@ -253,12 +248,10 @@ public class TraceLineLimitTransactionSelectorTest {
TestableTraceLineLimitTransactionSelector(
final SelectorsStateManager selectorsStateManager,
final LineaTracerConfiguration lineaTracerConfiguration,
final Map<String, Integer> moduleLimits,
final int overLimitCacheSize) {
super(
selectorsStateManager,
BigInteger.ONE,
moduleLimits,
LineaTransactionSelectorConfiguration.builder()
.overLinesLimitCacheSize(overLimitCacheSize)
.build(),