diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fc7d83487c..37366ec6217 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ### Additions and Improvements - Add error messages on authentication failures with username and password [#6212](https://github.com/hyperledger/besu/pull/6212) +- New `Sequenced` transaction pool. The pool is an evolution of the `legacy` pool and is likely to be more suitable to enterprise or permissioned chains than the `layered` transaction pool. Select to use this pool with `--tx-pool=sequenced`. Supports the same options as the `legacy` pool [#6211](https://github.com/hyperledger/besu/issues/6211) +- Set Ethereum Classic mainnet activation block for Spiral network upgrade [#6267](https://github.com/hyperledger/besu/pull/6267) ### Bug fixes diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index d8019908de8..49be39e96d6 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -78,6 +78,7 @@ import org.hyperledger.besu.cli.subcommands.PasswordSubCommand; import org.hyperledger.besu.cli.subcommands.PublicKeySubCommand; import org.hyperledger.besu.cli.subcommands.RetestethSubCommand; +import org.hyperledger.besu.cli.subcommands.TxParseSubCommand; import org.hyperledger.besu.cli.subcommands.ValidateConfigSubCommand; import org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand; import org.hyperledger.besu.cli.subcommands.operator.OperatorSubCommand; @@ -1493,6 +1494,8 @@ private void addSubCommands(final InputStream in) { jsonBlockImporterFactory, rlpBlockExporterFactory, commandLine.getOut())); + commandLine.addSubcommand( + TxParseSubCommand.COMMAND_NAME, new TxParseSubCommand(commandLine.getOut())); commandLine.addSubcommand( PublicKeySubCommand.COMMAND_NAME, new PublicKeySubCommand(commandLine.getOut())); commandLine.addSubcommand( diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/TransactionPoolOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/TransactionPoolOptions.java index 3b34c4d2a61..0b6718387b1 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/TransactionPoolOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/TransactionPoolOptions.java @@ -19,6 +19,7 @@ import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_LONG_FORMAT_HELP; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.SEQUENCED; import org.hyperledger.besu.cli.converter.DurationMillisConverter; import org.hyperledger.besu.cli.converter.FractionConverter; @@ -171,10 +172,10 @@ static class Layered { @CommandLine.ArgGroup( validate = false, - heading = "@|bold Tx Pool Legacy Implementation Options|@%n") - private final Legacy legacyOptions = new Legacy(); + heading = "@|bold Tx Pool Sequenced Implementation Options|@%n") + private final Sequenced sequencedOptions = new Sequenced(); - static class Legacy { + static class Sequenced { private static final String TX_POOL_RETENTION_HOURS = "--tx-pool-retention-hours"; private static final String TX_POOL_LIMIT_BY_ACCOUNT_PERCENTAGE = "--tx-pool-limit-by-account-percentage"; @@ -272,10 +273,10 @@ public static TransactionPoolOptions fromConfig(final TransactionPoolConfigurati config.getPendingTransactionsLayerMaxCapacityBytes(); options.layeredOptions.txPoolMaxPrioritized = config.getMaxPrioritizedTransactions(); options.layeredOptions.txPoolMaxFutureBySender = config.getMaxFutureBySender(); - options.legacyOptions.txPoolLimitByAccountPercentage = + options.sequencedOptions.txPoolLimitByAccountPercentage = config.getTxPoolLimitByAccountPercentage(); - options.legacyOptions.txPoolMaxSize = config.getTxPoolMaxSize(); - options.legacyOptions.pendingTxRetentionPeriod = config.getPendingTxRetentionPeriod(); + options.sequencedOptions.txPoolMaxSize = config.getTxPoolMaxSize(); + options.sequencedOptions.pendingTxRetentionPeriod = config.getPendingTxRetentionPeriod(); options.unstableOptions.txMessageKeepAliveSeconds = config.getUnstable().getTxMessageKeepAliveSeconds(); options.unstableOptions.eth65TrxAnnouncedBufferingPeriod = @@ -295,14 +296,14 @@ public void validate( final CommandLine commandLine, final GenesisConfigOptions genesisConfigOptions) { CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, - "Could not use legacy transaction pool options with layered implementation", + "Could not use legacy or sequenced transaction pool options with layered implementation", !txPoolImplementation.equals(LAYERED), - CommandLineUtils.getCLIOptionNames(Legacy.class)); + CommandLineUtils.getCLIOptionNames(Sequenced.class)); CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, - "Could not use layered transaction pool options with legacy implementation", - !txPoolImplementation.equals(LEGACY), + "Could not use layered transaction pool options with legacy or sequenced implementation", + !txPoolImplementation.equals(LEGACY) && !txPoolImplementation.equals(SEQUENCED), CommandLineUtils.getCLIOptionNames(Layered.class)); CommandLineUtils.failIfOptionDoesntMeetRequirement( @@ -327,9 +328,9 @@ public TransactionPoolConfiguration toDomainObject() { .pendingTransactionsLayerMaxCapacityBytes(layeredOptions.txPoolLayerMaxCapacity) .maxPrioritizedTransactions(layeredOptions.txPoolMaxPrioritized) .maxFutureBySender(layeredOptions.txPoolMaxFutureBySender) - .txPoolLimitByAccountPercentage(legacyOptions.txPoolLimitByAccountPercentage) - .txPoolMaxSize(legacyOptions.txPoolMaxSize) - .pendingTxRetentionPeriod(legacyOptions.pendingTxRetentionPeriod) + .txPoolLimitByAccountPercentage(sequencedOptions.txPoolLimitByAccountPercentage) + .txPoolMaxSize(sequencedOptions.txPoolMaxSize) + .pendingTxRetentionPeriod(sequencedOptions.pendingTxRetentionPeriod) .unstable( ImmutableTransactionPoolConfiguration.Unstable.builder() .txMessageKeepAliveSeconds(unstableOptions.txMessageKeepAliveSeconds) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java new file mode 100644 index 00000000000..221675c9dc5 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java @@ -0,0 +1,129 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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 org.hyperledger.besu.cli.subcommands; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hyperledger.besu.cli.subcommands.TxParseSubCommand.COMMAND_NAME; + +import org.hyperledger.besu.cli.util.VersionProvider; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.stream.Stream; + +import org.apache.tuweni.bytes.Bytes; +import picocli.CommandLine; + +/** + * txparse sub command implementing txparse spec from + * https://github.com/holiman/txparse/tree/main/cmd/txparse + */ +@CommandLine.Command( + name = COMMAND_NAME, + description = "Parse input transactions and return the sender, or an error.", + mixinStandardHelpOptions = true, + versionProvider = VersionProvider.class) +public class TxParseSubCommand implements Runnable { + + /** The constant COMMAND_NAME. */ + public static final String COMMAND_NAME = "txparse"; + + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. + @CommandLine.Option( + names = "--corpus-file", + arity = "1..1", + description = "file to read transaction data lines from, otherwise defaults to stdin") + private String corpusFile = null; + + static final BigInteger halfCurveOrder = + SignatureAlgorithmFactory.getInstance().getHalfCurveOrder(); + static final BigInteger chainId = new BigInteger("1", 10); + + private final PrintWriter out; + + /** + * Instantiates a new TxParse sub command. + * + * @param out the PrintWriter where validation results will be reported. + */ + public TxParseSubCommand(final PrintWriter out) { + this.out = out; + } + + @SuppressWarnings("StreamResourceLeak") + Stream fileStreamReader(final String filePath) { + try { + return Files.lines(Paths.get(filePath)) + // skip comments + .filter(line -> !line.startsWith("#")) + // strip out non-alphanumeric characters + .map(line -> line.replaceAll("[^a-zA-Z0-9]", "")); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void run() { + + Stream txStream; + if (corpusFile != null) { + txStream = fileStreamReader(corpusFile); + } else { + txStream = new BufferedReader(new InputStreamReader(System.in, UTF_8)).lines(); + } + + txStream.forEach( + line -> { + try { + Bytes bytes = Bytes.fromHexStringLenient(line); + dump(bytes); + } catch (Exception ex) { + err(ex.getMessage()); + } + }); + } + + void dump(final Bytes tx) { + try { + var transaction = TransactionDecoder.decodeOpaqueBytes(tx, EncodingContext.BLOCK_BODY); + + // https://github.com/hyperledger/besu/blob/5fe49c60b30fe2954c7967e8475c3b3e9afecf35/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java#L252 + if (transaction.getChainId().isPresent() && !transaction.getChainId().get().equals(chainId)) { + throw new Exception("wrong chain id"); + } + + // https://github.com/hyperledger/besu/blob/5fe49c60b30fe2954c7967e8475c3b3e9afecf35/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java#L270 + if (transaction.getS().compareTo(halfCurveOrder) > 0) { + throw new Exception("signature s out of range"); + } + out.println(transaction.getSender()); + + } catch (Exception ex) { + err(ex.getMessage()); + } + } + + void err(final String message) { + out.println("err: " + message); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index 5bc1c30bd61..7a83cd87515 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -147,8 +147,9 @@ public static Collection parameters() { new ForkId(Bytes.ofUnsignedInt(0x9007bfccL), 11700000L), new ForkId(Bytes.ofUnsignedInt(0xdb63a1caL), 13189133), new ForkId(Bytes.ofUnsignedInt(0x0f6bf187L), 14525000L), - new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L), - new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 0L)) + new ForkId(Bytes.ofUnsignedInt(0x7fd1bb25L), 19250000L), + new ForkId(Bytes.ofUnsignedInt(0xbe46d57cL), 0L), + new ForkId(Bytes.ofUnsignedInt(0xbe46d57cL), 0L)) }); } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java index 44718e96c67..ae00587c04d 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/ConfigurationOverviewBuilderTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.SEQUENCED; import static org.mockito.Mockito.mock; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -180,6 +181,13 @@ void setTxPoolImplementationLegacy() { assertThat(legacyTxPoolSelected).contains("Using LEGACY transaction pool implementation"); } + @Test + void setTxPoolImplementationSequenced() { + builder.setTxPoolImplementation(SEQUENCED); + final String sequencedTxPoolSelected = builder.build(); + assertThat(sequencedTxPoolSelected).contains("Using SEQUENCED transaction pool implementation"); + } + @Test void setWorldStateUpdateModeDefault() { builder.setWorldStateUpdateMode(EvmConfiguration.DEFAULT.worldUpdaterMode()); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java index 5b5fff5014e..d7031eb9a4f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LAYERED; import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.LEGACY; +import static org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration.Implementation.SEQUENCED; import org.hyperledger.besu.cli.converter.DurationMillisConverter; import org.hyperledger.besu.datatypes.Address; @@ -63,7 +64,7 @@ public void strictTxReplayProtection_default() { } @Test - public void pendingTransactionRetentionPeriod() { + public void pendingTransactionRetentionPeriodLegacy() { final int pendingTxRetentionHours = 999; internalTestSuccess( config -> @@ -73,6 +74,17 @@ public void pendingTransactionRetentionPeriod() { "--tx-pool=legacy"); } + @Test + public void pendingTransactionRetentionPeriodSequenced() { + final int pendingTxRetentionHours = 999; + internalTestSuccess( + config -> + assertThat(config.getPendingTxRetentionPeriod()).isEqualTo(pendingTxRetentionHours), + "--tx-pool-retention-hours", + String.valueOf(pendingTxRetentionHours), + "--tx-pool=sequenced"); + } + @Test public void disableLocalsDefault() { internalTestSuccess(config -> assertThat(config.getNoLocalPriority()).isFalse()); @@ -193,17 +205,24 @@ public void selectLegacyImplementationByArg() { "--tx-pool=legacy"); } + @Test + public void selectSequencedImplementationByArg() { + internalTestSuccess( + config -> assertThat(config.getTxPoolImplementation()).isEqualTo(SEQUENCED), + "--tx-pool=sequenced"); + } + @Test public void failIfLegacyOptionsWhenLayeredSelectedByDefault() { internalTestFailure( - "Could not use legacy transaction pool options with layered implementation", + "Could not use legacy or sequenced transaction pool options with layered implementation", "--tx-pool-max-size=1000"); } @Test public void failIfLegacyOptionsWhenLayeredSelectedByArg() { internalTestFailure( - "Could not use legacy transaction pool options with layered implementation", + "Could not use legacy or sequenced transaction pool options with layered implementation", "--tx-pool=layered", "--tx-pool-max-size=1000"); } @@ -211,11 +230,19 @@ public void failIfLegacyOptionsWhenLayeredSelectedByArg() { @Test public void failIfLayeredOptionsWhenLegacySelectedByArg() { internalTestFailure( - "Could not use layered transaction pool options with legacy implementation", + "Could not use layered transaction pool options with legacy or sequenced implementation", "--tx-pool=legacy", "--tx-pool-max-prioritized=1000"); } + @Test + public void failIfLayeredOptionsWhenSequencedSelectedByArg() { + internalTestFailure( + "Could not use layered transaction pool options with legacy or sequenced implementation", + "--tx-pool=sequenced", + "--tx-pool-max-prioritized=1000"); + } + @Test public void byDefaultNoPrioritySenders() { internalTestSuccess(config -> assertThat(config.getPrioritySenders()).isEmpty()); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommandTest.java new file mode 100644 index 00000000000..85839cc5b78 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommandTest.java @@ -0,0 +1,69 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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 org.hyperledger.besu.cli.subcommands; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +public class TxParseSubCommandTest { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(baos, UTF_8), true); + TxParseSubCommand txParseSubCommand = new TxParseSubCommand(writer); + + @Test + public void smokeTest() { + txParseSubCommand.dump( + Bytes.fromHexString( + "0x02f875018363bc5a8477359400850c570bd200825208943893d427c770de9b92065da03a8c825f13498da28702fbf8ccf8530480c080a0dd49141ecf93eeeaed5f3499a6103d6a9778e24a37b1f5c6a336c60c8a078c15a0511b51a3050771f66c1b779210a46a51be521a2446a3f87fc656dcfd1782aa5e")); + String output = baos.toString(UTF_8); + assertThat(output).isEqualTo("0xeb2629a2734e272bcc07bda959863f316f4bd4cf\n"); + } + + @Test + public void assertInvalidRlp() { + txParseSubCommand.dump( + Bytes.fromHexString( + "0x03f90124f9011e010516058261a89403040500000000000000000000000000000000006383000000f8b6f859940000000000000000000000000000000074657374f842a00100000000000000000000000000000000000000000000000000000000000000a00200000000000000000000000000000000000000000000000000000000000000f859940000000000000000000000000000000074657374f842a00100000000000000000000000000000000000000000000000000000000000000a002000000000000000000000000000000000000000000000000000000000000000fc080a082f96cae43a3f2554cad899a6e9168a3cd613454f82e93488f9b4c1a998cc814a06b7519cd0e3159d6ce9bf811ff3ca4e9c5d7ac63fc52142370a0725e4c5273b2c0c0c0")); + String output = baos.toString(UTF_8); + assertThat(output).startsWith("err: "); + assertThat(output).contains("arbitrary precision scalar"); + } + + @Test + public void assertValidRlp() { + txParseSubCommand.dump( + Bytes.fromHexString( + "0x03f9013f010516058261a89403040500000000000000000000000000000000006383000000f8b6f859940000000000000000000000000000000074657374f842a00100000000000000000000000000000000000000000000000000000000000000a00200000000000000000000000000000000000000000000000000000000000000f859940000000000000000000000000000000074657374f842a00100000000000000000000000000000000000000000000000000000000000000a002000000000000000000000000000000000000000000000000000000000000000fe1a0010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c44401401a0d98465c5489a09933e6428657f1fc4461d49febd8556c1c7e7053ed0be49cc4fa02c0d67e40aed75f87ea640cc47064d79f4383e24dec283ac6eb81e19da46cc26")); + String output = baos.toString(UTF_8); + assertThat(output).isEqualTo("0x730aa72228b55236de378f5267dfc77723b1380c\n"); + } + + @Test + public void assertInvalidChainId() { + txParseSubCommand.dump( + Bytes.fromHexString( + "0xf901fc303083303030803030b901ae30303030303030303030433030303030303030303030303030303030303030303030303030303030203030413030303030303030303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038390030000000002800380000413159000021000000002b0000000000003800000000003800000000000000000000002b633279315a00633200303041374222610063416200325832325a002543323861795930314130383058435931317a633043304239623900310031254363384361000023433158253041380037000027285839005a007937000000623700002761002b5a003937622e000000006300007863410000002a2e320000000000005a0000000000000037242778002039006120412e6362002138300000002a313030303030303030303030373030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030a03030303030303030303030303030303030303030303030303030303030303030a03030303030303030303030303030303030303030303030303030303030303030")); + String output = baos.toString(UTF_8); + assertThat(output).isEqualTo("err: wrong chain id\n"); + } +} diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index be337272e97..e516060da86 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -185,7 +185,7 @@ tx-pool-save-file="txpool.dump" tx-pool-layer-max-capacity=12345678 tx-pool-max-prioritized=9876 tx-pool-max-future-by-sender=321 -## Legacy +## Legacy/Sequenced tx-pool-retention-hours=999 tx-pool-max-size=1234 tx-pool-limit-by-account-percentage=0.017 diff --git a/config/src/main/resources/classic.json b/config/src/main/resources/classic.json index efbc5be4fcf..ea7c49e1fa3 100644 --- a/config/src/main/resources/classic.json +++ b/config/src/main/resources/classic.json @@ -13,10 +13,12 @@ "thanosBlock": 11700000, "magnetoBlock": 13189133, "mystiqueBlock": 14525000, + "spiralBlock": 19250000, "ethash": { }, "discovery" : { + "dns": "enrtree://AJE62Q4DUX4QMMXEHCSSCSC65TDHZYSMONSD64P3WULVLSF6MRQ3K@all.classic.blockd.info", "bootnodes" : [ "enode://8e73168affd8d445edda09c561d607081ca5d7963317caae2702f701eb6546b06948b7f8687a795de576f6a5f33c44828e25a90aa63de18db380a11e660dd06f@159.203.37.80:30303", "enode://2b1ef75e8b7119b6e0294f2e51ead2cf1a5400472452c199e9587727ada99e7e2b1199e36adcad6cbae65dce2410559546e4d83d8c93d45a559e723e56444c03@67.207.93.100:30303", diff --git a/crypto/services/build.gradle b/crypto/services/build.gradle index f6e082836c0..53b46d57473 100644 --- a/crypto/services/build.gradle +++ b/crypto/services/build.gradle @@ -32,11 +32,8 @@ dependencies { api project(':crypto:algorithms') api project(':plugin-api') - testImplementation 'junit:junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' - - testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } artifacts { testSupportArtifacts testSupportJar } diff --git a/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/KeyPairSecurityModuleTest.java b/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/KeyPairSecurityModuleTest.java index 68d369ae538..fac403e041d 100644 --- a/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/KeyPairSecurityModuleTest.java +++ b/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/KeyPairSecurityModuleTest.java @@ -20,26 +20,22 @@ import org.hyperledger.besu.crypto.SECPPublicKey; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.security.spec.ECPoint; import org.apache.tuweni.bytes.Bytes; import org.assertj.core.api.Assertions; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class KeyPairSecurityModuleTest { - @Rule public final TemporaryFolder temp = new TemporaryFolder(); + @TempDir public Path keyFile; @Test public void validatePublicKeyFromECPointCanBeConstructed() throws IOException { - final File keyDirectory = temp.newFolder(); - final File keyFile = new File(keyDirectory, "key"); - - final KeyPair keyPair = KeyPairUtil.loadKeyPair(keyFile); + final KeyPair keyPair = KeyPairUtil.loadKeyPair(keyFile.resolve("key")); final KeyPairSecurityModule keyPairSecurityModule = new KeyPairSecurityModule(keyPair); final ECPoint ecPoint = keyPairSecurityModule.getPublicKey().getW(); diff --git a/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/NodeKeyTest.java b/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/NodeKeyTest.java index 07008f06cbc..261271aee9b 100644 --- a/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/NodeKeyTest.java +++ b/crypto/services/src/test/java/org/hyperledger/besu/cryptoservices/NodeKeyTest.java @@ -21,12 +21,12 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.assertj.core.api.Assertions; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; public class NodeKeyTest { - @Before + @BeforeEach public void resetInstance() { SignatureAlgorithmFactory.resetInstance(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java index c205348f3a4..966283a66d6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldState.java @@ -299,7 +299,10 @@ private void updateAccountStorageState( worldStateUpdater.getAccountsToUpdate().get(updatedAddress); final BonsaiAccount accountOriginal = accountValue.getPrior(); final Hash storageRoot = - (accountOriginal == null) ? Hash.EMPTY_TRIE_HASH : accountOriginal.getStorageRoot(); + (accountOriginal == null + || worldStateUpdater.getStorageToClear().contains(updatedAddress)) + ? Hash.EMPTY_TRIE_HASH + : accountOriginal.getStorageRoot(); final StoredMerklePatriciaTrie storageTrie = createTrie( (location, key) -> diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java index f66fcd0f56f..f4a0da55c9e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java @@ -328,17 +328,6 @@ public void commit() { } if (tracked.getStorageWasCleared()) { updatedAccount.clearStorage(); - wrappedWorldView() - .getAllAccountStorage(updatedAddress, updatedAccount.getStorageRoot()) - .forEach( - (keyHash, entryValue) -> { - final StorageSlotKey storageSlotKey = - new StorageSlotKey(Hash.wrap(keyHash), Optional.empty()); - final UInt256 value = UInt256.fromBytes(RLP.decodeOne(entryValue)); - pendingStorageUpdates.put( - storageSlotKey, new BonsaiValue<>(value, null, true)); - }); - updatedAccount.setStorageRoot(Hash.EMPTY_TRIE_HASH); } tracked.getUpdatedStorage().forEach(updatedAccount::setStorageValue); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java index e30d24c158f..f6ef30667e6 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolConfiguration.java @@ -50,8 +50,9 @@ default int getTxMessageKeepAliveSeconds() { } enum Implementation { - LEGACY, - LAYERED; + LEGACY, // Remove in future version + LAYERED, + SEQUENCED; // Synonym for LEGACY } String DEFAULT_SAVE_FILE_NAME = "txpool.dump"; diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java index d36a0b6a87d..b2dd41bbfa5 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; import org.hyperledger.besu.evm.gascalculator.ByzantiumGasCalculator; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; import org.hyperledger.besu.evm.gascalculator.GasCalculator; @@ -33,6 +34,7 @@ import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; +import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator; import org.hyperledger.besu.evm.gascalculator.TangerineWhistleGasCalculator; import org.hyperledger.besu.testutil.JsonTestParameters; @@ -54,7 +56,8 @@ private static TransactionValidator transactionValidator(final String name) { return REFERENCE_TEST_PROTOCOL_SCHEDULES .getByName(name) .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()) - .getTransactionValidatorFactory().get(); + .getTransactionValidatorFactory() + .get(); } private static final String TEST_CONFIG_FILE_DIR_PATH = "TransactionTests/"; @@ -62,7 +65,9 @@ private static TransactionValidator transactionValidator(final String name) { public static Stream getTestParametersForConfig() { return JsonTestParameters.create(TransactionTestCaseSpec.class) .generator((name, fullPath, spec, collector) -> collector.add(name, fullPath, spec, true)) - .generate(TEST_CONFIG_FILE_DIR_PATH).stream().map(params -> Arguments.of(params[0], params[1])); + .generate(TEST_CONFIG_FILE_DIR_PATH) + .stream() + .map(params -> Arguments.of(params[0], params[1])); } @ParameterizedTest(name = "Name: {0}") @@ -125,8 +130,30 @@ public void london(final String name, final TransactionTestCaseSpec spec) { milestone(spec, name, "London", new LondonGasCalculator(), Optional.of(Wei.of(0))); } + @ParameterizedTest(name = "Name: {0}") + @MethodSource("getTestParametersForConfig") + public void merge(final String name, final TransactionTestCaseSpec spec) { + milestone(spec, name, "Merge", new LondonGasCalculator(), Optional.of(Wei.of(0))); + } + + @ParameterizedTest(name = "Name: {0}") + @MethodSource("getTestParametersForConfig") + public void shanghai(final String name, final TransactionTestCaseSpec spec) { + milestone(spec, name, "Shanghai", new ShanghaiGasCalculator(), Optional.of(Wei.of(0))); + } + + @ParameterizedTest(name = "Name: {0}") + @MethodSource("getTestParametersForConfig") + public void cancun(final String name, final TransactionTestCaseSpec spec) { + milestone(spec, name, "Cancun", new CancunGasCalculator(), Optional.of(Wei.of(0))); + } + public void milestone( - final TransactionTestCaseSpec spec, final String name, final String milestone, final GasCalculator gasCalculator, final Optional baseFee) { + final TransactionTestCaseSpec spec, + final String name, + final String milestone, + final GasCalculator gasCalculator, + final Optional baseFee) { final TransactionTestCaseSpec.Expectation expected = spec.expectation(milestone); diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTestCaseSpec.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTestCaseSpec.java index 7f9c3cb7c63..7ce7384e1ab 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTestCaseSpec.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTestCaseSpec.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Assumptions; /** A Transaction test case specification. */ @JsonIgnoreProperties({"_info"}) @@ -109,9 +110,7 @@ public Bytes getRlp() { public Expectation expectation(final String milestone) { final Expectation expectation = expectations.get(milestone); - if (expectation == null) { - throw new IllegalStateException("Expectation for milestone " + milestone + " not found"); - } + Assumptions.assumeFalse(expectation == null, () -> "No expectation for milestone " + milestone); return expectation; } diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/rlp/RLPRefTest.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/rlp/RLPRefTest.java index a4eff43c98d..b6d01dae83f 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/rlp/RLPRefTest.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/rlp/RLPRefTest.java @@ -16,12 +16,13 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; -import org.assertj.core.api.Assertions; import org.hyperledger.besu.ethereum.rlp.util.RLPTestUtil; import org.hyperledger.besu.testutil.JsonTestParameters; import java.util.stream.Stream; +import org.apache.tuweni.bytes.Bytes; +import org.assertj.core.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -29,23 +30,45 @@ /** The Ethereum reference RLP tests. */ public class RLPRefTest { - private static final String TEST_CONFIG_FILES = "RLPTests/rlptest.json"; + private static final String[] TEST_CONFIG_FILES = { + "RLPTests/rlptest.json", "RLPTests/invalidRLPTest.json" + }; + + private static final Bytes INVALID = Bytes.fromHexString("0x494e56414c4944"); public static Stream getTestParametersForConfig() { - return JsonTestParameters.create(RLPRefTestCaseSpec.class).generate(TEST_CONFIG_FILES).stream().map(params -> Arguments.of(params[0], params[1], params[2])); + return JsonTestParameters.create(RLPRefTestCaseSpec.class).generate(TEST_CONFIG_FILES).stream() + .map(params -> Arguments.of(params[0], params[1], params[2])); } @ParameterizedTest(name = "Name: {0}") @MethodSource("getTestParametersForConfig") public void encode(final String name, final RLPRefTestCaseSpec spec, final boolean runTest) { assumeTrue(runTest, "Test was blacklisted"); - Assertions.assertThat(RLPTestUtil.encode(spec.getIn())).isEqualTo(spec.getOut()); + if (!spec.getIn().equals(INVALID)) { + Assertions.assertThat(RLPTestUtil.encode(spec.getIn())).isEqualTo(spec.getOut()); + } } @ParameterizedTest(name = "Name: {0}") @MethodSource("getTestParametersForConfig") public void decode(final String name, final RLPRefTestCaseSpec spec, final boolean runTest) { assumeTrue(runTest, "Test was blacklisted"); - Assertions.assertThat(RLPTestUtil.decode(spec.getOut())).isEqualTo(spec.getIn()); + if (spec.getIn().equals(INVALID)) { + Assertions.assertThatThrownBy(() -> RLPTestUtil.decode(spec.getOut())) + .isInstanceOf(RLPException.class); + Assertions.assertThatThrownBy(() -> decode2(RLP.input(spec.getOut()))) + .isInstanceOf(RLPException.class); + } else { + Assertions.assertThat(RLPTestUtil.decode(spec.getOut())).isEqualTo(spec.getIn()); + } + } + + private static Object decode2(final RLPInput in) { + if (in.nextIsList()) { + return in.readList(RLPRefTest::decode2); + } else { + return in.readBytes(); + } } }