diff --git a/CHANGELOG.md b/CHANGELOG.md index 7710f8e7b95..9c6cb373ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237) - Implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262) - Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352) +- `--Xbonsai-parallel-tx-processing-enabled` option enables executing transactions in parallel during block processing for Bonsai nodes ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) 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 7216d9ebd66..198c26fe2a8 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1901,6 +1901,8 @@ public BesuControllerBuilder getControllerBuilder() { .privacyParameters(privacyParameters()) .clock(Clock.systemUTC()) .isRevertReasonEnabled(isRevertReasonEnabled) + .isParallelTxProcessingEnabled( + dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled()) .storageProvider(storageProvider) .gasLimitCalculator( miningParametersSupplier.get().getTargetGasLimit().isPresent() diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java index 69cf819cb4b..fc92a7e5dd9 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java @@ -122,6 +122,14 @@ public static class Unstable { "Enables code storage using code hash instead of by account hash. (default: ${DEFAULT-VALUE})") private boolean bonsaiCodeUsingCodeHashEnabled = DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED; + @CommandLine.Option( + hidden = true, + names = {"--Xbonsai-parallel-tx-processing-enabled"}, + arity = "1", + description = + "Enables parallelization of transactions to optimize processing speed by concurrently loading and executing necessary data in advance. (default: ${DEFAULT-VALUE})") + private Boolean isParallelTxProcessingEnabled = false; + /** Default Constructor. */ Unstable() {} } @@ -142,40 +150,48 @@ public static DataStorageOptions create() { * @param syncMode the sync mode */ public void validate(final CommandLine commandLine, final SyncMode syncMode) { - if (DataStorageFormat.BONSAI == dataStorageFormat && bonsaiLimitTrieLogsEnabled) { - if (SyncMode.FULL == syncMode) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - "Cannot enable %s with sync-mode %s. You must set %s or use a different sync-mode", - BONSAI_LIMIT_TRIE_LOGS_ENABLED, - SyncMode.FULL, - BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false")); - } - if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d", - MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT)); - } - if (bonsaiTrieLogPruningWindowSize <= 0) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0", - bonsaiTrieLogPruningWindowSize)); + if (DataStorageFormat.BONSAI == dataStorageFormat) { + if (bonsaiLimitTrieLogsEnabled) { + if (SyncMode.FULL == syncMode) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + "Cannot enable %s with sync-mode %s. You must set %s or use a different sync-mode", + BONSAI_LIMIT_TRIE_LOGS_ENABLED, + SyncMode.FULL, + BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false")); + } + if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d", + MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT)); + } + if (bonsaiTrieLogPruningWindowSize <= 0) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0", + bonsaiTrieLogPruningWindowSize)); + } + if (bonsaiTrieLogPruningWindowSize <= bonsaiMaxLayersToLoad) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + + "=%d must be greater than " + + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + + "=%d", + bonsaiTrieLogPruningWindowSize, + bonsaiMaxLayersToLoad)); + } } - if (bonsaiTrieLogPruningWindowSize <= bonsaiMaxLayersToLoad) { + } else { + if (unstableOptions.isParallelTxProcessingEnabled) { throw new CommandLine.ParameterException( commandLine, - String.format( - BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE - + "=%d must be greater than " - + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD - + "=%d", - bonsaiTrieLogPruningWindowSize, - bonsaiMaxLayersToLoad)); + "Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai."); } } } @@ -198,6 +214,8 @@ public static DataStorageOptions fromConfig(final DataStorageConfiguration domai domainObject.getUnstable().getBonsaiFullFlatDbEnabled(); dataStorageOptions.unstableOptions.bonsaiCodeUsingCodeHashEnabled = domainObject.getUnstable().getBonsaiCodeStoredByCodeHashEnabled(); + dataStorageOptions.unstableOptions.isParallelTxProcessingEnabled = + domainObject.getUnstable().isParallelTxProcessingEnabled(); return dataStorageOptions; } @@ -214,6 +232,7 @@ public DataStorageConfiguration toDomainObject() { ImmutableDataStorageConfiguration.Unstable.builder() .bonsaiFullFlatDbEnabled(unstableOptions.bonsaiFullFlatDbEnabled) .bonsaiCodeStoredByCodeHashEnabled(unstableOptions.bonsaiCodeUsingCodeHashEnabled) + .isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled) .build()) .build(); } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 20f3ca8ef61..ddb75fcdedc 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -203,6 +203,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides private int numberOfBlocksToCache = 0; + /** whether parallel transaction processing is enabled or not */ + protected boolean isParallelTxProcessingEnabled; + /** Instantiates a new Besu controller builder. */ protected BesuControllerBuilder() {} @@ -512,6 +515,20 @@ public BesuControllerBuilder randomPeerPriority(final Boolean randomPeerPriority return this; } + /** + * Sets whether parallel transaction processing is enabled. When parallel transaction processing + * is enabled, transactions within a block can be processed in parallel and potentially improving + * performance + * + * @param isParallelTxProcessingEnabled true to enable parallel transaction + * @return the besu controller + */ + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + return this; + } + /** * Build besu controller. * diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index c1274240694..b4ada605498 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -136,7 +136,9 @@ protected ProtocolSchedule createProtocolSchedule() { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java index f6693322029..0d0f8d2fd87 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java @@ -358,6 +358,15 @@ public BesuControllerBuilder isRevertReasonEnabled(final boolean isRevertReasonE return super.isRevertReasonEnabled(isRevertReasonEnabled); } + @Override + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + besuControllerBuilderSchedule + .values() + .forEach(b -> b.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled)); + return super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled); + } + @Override public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { besuControllerBuilderSchedule.values().forEach(b -> b.gasLimitCalculator(gasLimitCalculator)); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 473549e0bd7..b8d4d2645e0 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -291,7 +291,9 @@ protected ProtocolSchedule createProtocolSchedule() { bftExtraDataCodec().get(), evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index 27570483c12..e0fbed608ab 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -99,7 +99,9 @@ protected ProtocolSchedule createProtocolSchedule() { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index cdd46ea5b98..f5fc75959e1 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -177,7 +177,9 @@ protected ProtocolSchedule createProtocolSchedule() { privacyParameters, isRevertReasonEnabled, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 795136ded5d..ab2dbce3f13 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -329,7 +329,9 @@ protected ProtocolSchedule createProtocolSchedule() { bftExtraDataCodec().get(), evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index cdf5413fff2..d7b701b4c5d 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -374,6 +374,13 @@ public BesuControllerBuilder isRevertReasonEnabled(final boolean isRevertReasonE return propagateConfig(z -> z.isRevertReasonEnabled(isRevertReasonEnabled)); } + @Override + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled); + return propagateConfig(z -> z.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled)); + } + @Override public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { super.gasLimitCalculator(gasLimitCalculator); diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index fe5077acc6a..28d4c77036f 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.forkid.ForkIdManager; import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Collection; import java.util.List; @@ -177,12 +178,21 @@ private static MilestoneStreamingTransitionProtocolSchedule createSchedule( new MilestoneStreamingProtocolSchedule( (DefaultProtocolSchedule) MainnetProtocolSchedule.fromConfig( - configOptions, MiningParameters.MINING_DISABLED, new BadBlockManager())); + configOptions, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem())); MilestoneStreamingProtocolSchedule postMergeProtocolSchedule = new MilestoneStreamingProtocolSchedule( (DefaultProtocolSchedule) MergeProtocolSchedule.create( - configOptions, false, MiningParameters.MINING_DISABLED, new BadBlockManager())); + configOptions, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem())); final MilestoneStreamingTransitionProtocolSchedule schedule = new MilestoneStreamingTransitionProtocolSchedule( preMergeProtocolSchedule, postMergeProtocolSchedule); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index c92a3a5bda4..8a6a5781198 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -276,6 +276,8 @@ public void initMocks() throws Exception { when(mockControllerBuilder.privacyParameters(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.clock(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.isParallelTxProcessingEnabled(false)) + .thenReturn(mockControllerBuilder); when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder); diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java index 91013ab97c9..cd197556386 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -64,6 +65,9 @@ public class CliqueProtocolSchedule { * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static ProtocolSchedule create( @@ -74,7 +78,9 @@ public static ProtocolSchedule create( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions(); @@ -110,7 +116,9 @@ public static ProtocolSchedule create( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -124,6 +132,9 @@ public static ProtocolSchedule create( * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ @VisibleForTesting @@ -134,7 +145,9 @@ public static ProtocolSchedule create( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, forksSchedule, @@ -143,7 +156,9 @@ public static ProtocolSchedule create( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } private static ProtocolSpecBuilder applyCliqueSpecificModifications( diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java index 35f959e45bd..5cbdbb6d06e 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java @@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.time.Instant; import java.util.List; @@ -68,7 +69,9 @@ public void protocolSpecsAreCreatedAtBlockDefinedInJson() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1)); final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockHeader(blockHeader(2)); @@ -92,7 +95,9 @@ public void parametersAlignWithMainnetWithAdjustments() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .getByBlockHeader(blockHeader(0)); assertThat(homestead.getName()).isEqualTo("Frontier"); @@ -116,7 +121,9 @@ public void zeroEpochLengthThrowsException() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())) + new BadBlockManager(), + false, + new NoOpMetricsSystem())) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Epoch length in config must be greater than zero"); } @@ -136,7 +143,9 @@ public void negativeEpochLengthThrowsException() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())) + new BadBlockManager(), + false, + new NoOpMetricsSystem())) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Epoch length in config must be greater than zero"); } @@ -160,7 +169,9 @@ public void shouldValidateBaseFeeMarketTransition() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); BlockHeader emptyFrontierParent = headerBuilder diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 485b2aff79d..ec10630df9c 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -106,7 +106,9 @@ void setup() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey()); validatorList.add(otherAddress); diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index bb69aaff483..9502d00a192 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -105,7 +105,9 @@ public void setup() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); cliqueEthContext = mock(EthContext.class, RETURNS_DEEP_STUBS); blockHeaderBuilder = new BlockHeaderTestFixture(); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java index da81ce80b7c..311bf30faef 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -58,6 +59,9 @@ protected BaseBftProtocolScheduleBuilder() {} * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem metricsSystem A metricSystem instance to be able to expose metrics in the + * underlying calls * @return the protocol schedule */ public BftProtocolSchedule createProtocolSchedule( @@ -68,7 +72,9 @@ public BftProtocolSchedule createProtocolSchedule( final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final Map> specMap = new HashMap<>(); forksSchedule @@ -90,7 +96,9 @@ public BftProtocolSchedule createProtocolSchedule( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); return new BftProtocolSchedule((DefaultProtocolSchedule) protocolSchedule); } diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java index 4e3cab78e7f..02689d52af1 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.List; @@ -177,7 +178,9 @@ private BftProtocolSchedule createProtocolSchedule( false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); return new BftProtocolSchedule( (DefaultProtocolSchedule) protocolScheduleBuilder.createProtocolSchedule()); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java index 9b05bd7a365..e23664fd8d3 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.List; @@ -245,7 +246,9 @@ protected BlockHeaderValidator.Builder createBlockHeaderRuleset( bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private BftConfigOptions createBftConfig(final BigInteger blockReward) { diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 55a2f3551a1..2d620c56321 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -333,7 +333,9 @@ private static ControllerAndState createControllerAndFinalState( IBFT_EXTRA_DATA_ENCODER, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ///////////////////////////////////////////////////////////////////////////////////// // From here down is BASICALLY taken from IbftBesuController diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java index 5cad697c537..0789f2e8981 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Optional; @@ -46,6 +47,9 @@ protected IbftProtocolScheduleBuilder() {} * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -56,7 +60,9 @@ public static BftProtocolSchedule create( final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new IbftProtocolScheduleBuilder() .createProtocolSchedule( config, @@ -66,7 +72,9 @@ public static BftProtocolSchedule create( bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -78,6 +86,9 @@ public static BftProtocolSchedule create( * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -86,7 +97,9 @@ public static BftProtocolSchedule create( final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, forksSchedule, @@ -95,7 +108,9 @@ public static BftProtocolSchedule create( bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java index 611399fd55b..e5551ff3f31 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java @@ -45,6 +45,7 @@ import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Collection; @@ -103,7 +104,9 @@ private BftProtocolSchedule createProtocolSchedule( bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private boolean validateHeader( diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java index 25c5c1d10b8..1b86896f36f 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java @@ -121,7 +121,9 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( bftExtraDataEncoder, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolContext protContext = new ProtocolContext( blockchain, diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java index 68e0ee5efe5..b388b80a3f1 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java @@ -79,6 +79,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.util.Subscribers; import java.math.BigInteger; @@ -184,7 +185,9 @@ public void setup() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ProtocolSchedule protocolSchedule = new BftProtocolSchedule( diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java index ff92319ae39..abbc3b130aa 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -49,19 +50,24 @@ public class MergeProtocolSchedule { * @param isRevertReasonEnabled the is revert reason enabled * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return the protocol schedule */ public static ProtocolSchedule create( final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -72,6 +78,7 @@ public static ProtocolSchedule create( * @param isRevertReasonEnabled the is revert reason enabled * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return the protocol schedule */ public static ProtocolSchedule create( @@ -79,7 +86,9 @@ public static ProtocolSchedule create( final PrivacyParameters privacyParameters, final boolean isRevertReasonEnabled, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { Map> postMergeModifications = new HashMap<>(); @@ -98,7 +107,9 @@ public static ProtocolSchedule create( isRevertReasonEnabled, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index faab15dac4a..8600344cefe 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -65,17 +66,30 @@ public TransitionProtocolSchedule( * milestone starting points * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return an initialised TransitionProtocolSchedule using post-merge defaults */ public static TransitionProtocolSchedule fromConfig( final GenesisConfigOptions genesisConfigOptions, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSchedule preMergeProtocolSchedule = - MainnetProtocolSchedule.fromConfig(genesisConfigOptions, miningParameters, badBlockManager); + MainnetProtocolSchedule.fromConfig( + genesisConfigOptions, + miningParameters, + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); ProtocolSchedule postMergeProtocolSchedule = MergeProtocolSchedule.create( - genesisConfigOptions, false, miningParameters, badBlockManager); + genesisConfigOptions, + false, + miningParameters, + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); return new TransitionProtocolSchedule( preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get()); } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java index b1f7414e453..0d4aede3a14 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.evm.operation.InvalidOperation; import org.hyperledger.besu.evm.operation.PrevRanDaoOperation; import org.hyperledger.besu.evm.operation.Push0Operation; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; @@ -48,7 +49,12 @@ public void protocolSpecsAreCreatedAtBlockDefinedInJson() { final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1)); final ProtocolSpec londonSpec = protocolSchedule.getByBlockHeader(blockHeader(1559)); @@ -64,7 +70,12 @@ public void mergeSpecificModificationsAreUnappliedForShanghai() { final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final long lastParisBlockNumber = 17034869L; final ProtocolSpec parisSpec = @@ -100,7 +111,12 @@ public void mergeSpecificModificationsAreUnappliedForCancun_whenShanghaiNotConfi final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec parisSpec = protocolSchedule.getByBlockHeader( @@ -128,7 +144,12 @@ public void mergeSpecificModificationsAreUnappliedForAllMainnetForksAfterParis() final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final long lastParisBlockNumber = 17034869L; final ProtocolSpec parisSpec = @@ -160,7 +181,9 @@ public void parametersAlignWithMainnetWithAdjustments() { GenesisConfigFile.DEFAULT.getConfigOptions(), false, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .getByBlockHeader(blockHeader(0)); assertThat(london.getName()).isEqualTo("Paris"); diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java index 54099f868cb..dcfe5f98e34 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.net.URI; @@ -56,6 +57,8 @@ default ProtocolSchedule getMergeProtocolSchedule() { getPosGenesisConfigFile().getConfigOptions(), false, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } } diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index 5cf74f9458c..3467dce9fb2 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -437,7 +437,9 @@ private static ControllerAndState createControllerAndFinalState( BFT_EXTRA_DATA_ENCODER, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final BftValidatorOverrides validatorOverrides = convertBftForks(qbftForks); final TransactionSimulator transactionSimulator = diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java index 58a50efa261..44c7ddfba8c 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Optional; @@ -50,6 +51,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param evmConfiguration the evm configuration * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -60,7 +64,9 @@ public static BftProtocolSchedule create( final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new QbftProtocolScheduleBuilder() .createProtocolSchedule( config, @@ -70,7 +76,9 @@ public static BftProtocolSchedule create( bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -82,6 +90,9 @@ public static BftProtocolSchedule create( * @param evmConfiguration the evm configuration * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -90,7 +101,9 @@ public static BftProtocolSchedule create( final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, qbftForksSchedule, @@ -99,7 +112,9 @@ public static BftProtocolSchedule create( bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -111,6 +126,9 @@ public static BftProtocolSchedule create( * @param bftExtraDataCodec the bft extra data codec * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static ProtocolSchedule create( @@ -119,7 +137,9 @@ public static ProtocolSchedule create( final boolean isRevertReasonEnabled, final BftExtraDataCodec bftExtraDataCodec, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, qbftForksSchedule, @@ -128,7 +148,9 @@ public static ProtocolSchedule create( bftExtraDataCodec, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java index 07b3be34b44..020d6e0e5ae 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Collection; @@ -138,7 +139,9 @@ private BftProtocolSchedule createProtocolSchedule( bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private boolean validateHeader( diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java index 0aa1f7843bc..71ea4131a3b 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java @@ -78,6 +78,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.util.Subscribers; import java.math.BigInteger; @@ -184,7 +185,9 @@ BftContext.class, validators, new QbftExtraDataCodec()), false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ProtocolSchedule protocolSchedule = new BftProtocolSchedule( diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java index 63449d74b50..ad4fe7ddb15 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java @@ -34,6 +34,13 @@ public Blake2bfMessageDigest() { super(new Blake2bfDigest()); } + @Override + public Blake2bfMessageDigest clone() throws CloneNotSupportedException { + Blake2bfMessageDigest cloned = (Blake2bfMessageDigest) super.clone(); + cloned.digest = ((Blake2bfDigest) this.digest).clone(); + return cloned; + } + /** * Implementation of the `F` compression function of the Blake2b cryptographic hash function. * @@ -43,7 +50,7 @@ public Blake2bfMessageDigest() { * *

Optimized for 64-bit platforms */ - public static class Blake2bfDigest implements Digest { + public static class Blake2bfDigest implements Digest, Cloneable { /** The constant MESSAGE_LENGTH_BYTES. */ public static final int MESSAGE_LENGTH_BYTES = 213; @@ -71,18 +78,18 @@ public static class Blake2bfDigest implements Digest { // buffer which holds serialized input for this compression function // [ 4 bytes for rounds ][ 64 bytes for h ][ 128 bytes for m ] // [ 8 bytes for t_0 ][ 8 bytes for t_1 ][ 1 byte for f ] - private final byte[] buffer; + private byte[] buffer; private int bufferPos; // deserialized inputs for f compression - private final long[] h; - private final long[] m; - private final long[] t; + private long[] h; + private long[] m; + private long[] t; private boolean f; private long rounds; // unsigned integer represented as long - private final long[] v; + private long[] v; private static boolean useNative; static { @@ -112,6 +119,17 @@ public static class Blake2bfDigest implements Digest { v = new long[16]; } + @Override + public Blake2bfDigest clone() throws CloneNotSupportedException { + Blake2bfDigest cloned = (Blake2bfDigest) super.clone(); + cloned.buffer = this.buffer.clone(); + cloned.h = this.h.clone(); + cloned.m = this.m.clone(); + cloned.t = this.t.clone(); + cloned.v = this.v.clone(); + return cloned; + } + /** Disable native. */ public static void disableNative() { useNative = false; diff --git a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java index bd00dc7dae1..390d7d41438 100644 --- a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java +++ b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java @@ -17,6 +17,13 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.IntStream; + import org.bouncycastle.util.Pack; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -29,6 +36,16 @@ */ public class Blake2bfMessageDigestTest { + private static final SecureRandom SECURE_RANDOM; + + static { + try { + SECURE_RANDOM = SecureRandom.getInstanceStrong(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + private Blake2bfMessageDigest messageDigest; // output when input is all 0 @@ -124,6 +141,39 @@ public void throwsIfEmptyBufferUpdatedLargeByteArray() { .isInstanceOf(IllegalArgumentException.class); } + @SuppressWarnings("unchecked") + @Test + public void testDigestThreadSafety() throws ExecutionException, InterruptedException { + final byte[] input = new byte[213]; + ; + SECURE_RANDOM.nextBytes(input); + int numberOfHashes = 10; + + CompletableFuture[] futures = + IntStream.range(0, numberOfHashes) + .mapToObj( + i -> + CompletableFuture.supplyAsync( + () -> { + try { + MessageDigest clonedDigest = messageDigest.clone(); + clonedDigest.update(input); + byte[] digest = clonedDigest.digest(); + return digest; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + })) + .toArray(CompletableFuture[]::new); + + CompletableFuture.allOf(futures).get(); + + byte[] expectedHash = futures[0].get(); + for (CompletableFuture future : futures) { + assertThat(expectedHash).isEqualTo(future.get()); + } + } + @ParameterizedTest @CsvFileSource(resources = "eip152TestCases.csv", numLinesToSkip = 1) public void eip152TestCases(final String hexIn, final String hexExpected) { diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java index a8bf7c9afd1..8404453cf18 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java @@ -94,7 +94,7 @@ public boolean equals(final Object o) { @Override public int hashCode() { - return Objects.hash(slotHash.hashCode()); + return slotHash.hashCode(); } @Override diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java index 2a62331d336..3e261abf6d7 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.util.RawBlockIterator; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.net.URL; import java.nio.file.Paths; @@ -46,7 +47,9 @@ public BlockchainImporter(final URL blocksUrl, final String genesisJson) throws MainnetProtocolSchedule.fromConfig( GenesisConfigFile.fromConfig(genesisJson).getConfigOptions(), MiningParameters.newDefault(), - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final BlockHeaderFunctions blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); blocks = new ArrayList<>(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index af5228dc06e..80626ef2fc6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -109,7 +109,9 @@ public void initServerAndClient() throws Exception { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 6ae5d37a0fc..0fb55fdf344 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -138,7 +138,11 @@ public static void initServerAndClient() throws Exception { blockchainQueries, synchronizer, MainnetProtocolSchedule.fromConfig( - genesisConfigOptions, MiningParameters.MINING_DISABLED, new BadBlockManager()), + genesisConfigOptions, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index f8c9dbc18fb..a2a856333ea 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -118,7 +118,9 @@ public static void initServerAndClient() throws Exception { new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index 2f62e490beb..1d3a3a087a7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -123,7 +123,9 @@ public void initServer() throws Exception { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index 2ff0833bc69..684f843d2fb 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -111,7 +111,9 @@ public void beforeEach() { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index e650f9d490b..b6d7fa67f81 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -112,7 +112,9 @@ public void initServer() throws Exception { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 5fa137e312c..75927c45130 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -176,7 +176,9 @@ public void before() throws URISyntaxException { MainnetProtocolSchedule.fromConfig( genesisConfigOptions, MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index 2444d9db7de..946d4ab09d3 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java @@ -395,7 +395,9 @@ private AbstractBlockCreator createBlockCreator(final ProtocolSpecAdapters proto false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index d70589ae832..c6ee454241a 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -223,7 +223,9 @@ public void emptyPendingTransactionsResultsInEmptyVettingResult() { GenesisConfigFile.fromResource("/dev.json").getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final MainnetTransactionProcessor mainnetTransactionProcessor = protocolSchedule.getByBlockHeader(blockHeader(0)).getTransactionProcessor(); diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java index 62063845342..416e5fd2349 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.number.Fraction; @@ -60,7 +61,9 @@ protected ProtocolSchedule createProtocolSchedule() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index e9bfcfb762a..a59841d4f4f 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -43,6 +43,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.number.Fraction; @@ -71,7 +72,9 @@ protected ProtocolSchedule createProtocolSchedule() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java index 2cd5bc5e9e2..7e3c01200ce 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java @@ -97,8 +97,10 @@ void createMainnetBlock1() throws IOException { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); @@ -158,8 +160,10 @@ void createMainnetBlock1_fixedDifficulty1() { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); @@ -209,8 +213,10 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsFalse() { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) @@ -285,8 +291,10 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsTrue() { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java index b7f8395d92f..b86b2b0de22 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; /** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */ public class FixedDifficultyProtocolSchedule { @@ -32,7 +33,9 @@ public static ProtocolSchedule create( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new ProtocolScheduleBuilder( config, ProtocolSpecAdapters.create( @@ -43,7 +46,9 @@ public static ProtocolSchedule create( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -52,27 +57,35 @@ public static ProtocolSchedule create( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } public static ProtocolSchedule create( final GenesisConfigOptions config, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, false, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 8ecfa453d9f..480a1d8d7ab 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.operation.BlockHashOperation; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -110,57 +111,67 @@ public BlockProcessingResult processBlock( protocolSpec.getBlockHashProcessor().processBlockHashes(blockchain, worldState, blockHeader); final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain); - for (final Transaction transaction : transactions) { + final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); + + Optional maybeParentHeader = + blockchain.getBlockHeader(blockHeader.getParentHash()); + + Wei blobGasPrice = + maybeParentHeader + .map( + parentHeader -> + protocolSpec + .getFeeMarket() + .blobGasPricePerGas( + calculateExcessBlobGasForParent(protocolSpec, parentHeader))) + .orElse(Wei.ZERO); + + final Optional preProcessingContext = + runBlockPreProcessing( + worldState, + privateMetadataUpdater, + blockHeader, + transactions, + miningBeneficiary, + blockHashLookup, + blobGasPrice); + + for (int i = 0; i < transactions.size(); i++) { + final Transaction transaction = transactions.get(i); if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); } + final WorldUpdater blockUpdater = worldState.updater(); - final WorldUpdater worldStateUpdater = worldState.updater(); - - final Address miningBeneficiary = - miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); - - Optional maybeParentHeader = - blockchain.getBlockHeader(blockHeader.getParentHash()); - - Wei blobGasPrice = - maybeParentHeader - .map( - parentHeader -> - protocolSpec - .getFeeMarket() - .blobGasPricePerGas( - calculateExcessBlobGasForParent(protocolSpec, parentHeader))) - .orElse(Wei.ZERO); - - final TransactionProcessingResult result = - transactionProcessor.processTransaction( - worldStateUpdater, + TransactionProcessingResult transactionProcessingResult = + getTransactionProcessingResult( + preProcessingContext, + worldState, + blockUpdater, + privateMetadataUpdater, blockHeader, - transaction, + blobGasPrice, miningBeneficiary, - OperationTracer.NO_TRACING, - blockHashLookup, - true, - TransactionValidationParams.processingBlock(), - privateMetadataUpdater, - blobGasPrice); - if (result.isInvalid()) { + transaction, + i, + blockHashLookup); + if (transactionProcessingResult.isInvalid()) { String errorMessage = MessageFormat.format( "Block processing error: transaction invalid {0}. Block {1} Transaction {2}", - result.getValidationResult().getErrorMessage(), + transactionProcessingResult.getValidationResult().getErrorMessage(), blockHeader.getHash().toHexString(), transaction.getHash().toHexString()); LOG.info(errorMessage); if (worldState instanceof BonsaiWorldState) { - ((BonsaiWorldStateUpdateAccumulator) worldStateUpdater).reset(); + ((BonsaiWorldStateUpdateAccumulator) blockUpdater).reset(); } return new BlockProcessingResult(Optional.empty(), errorMessage); } - worldStateUpdater.commit(); - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); + blockUpdater.commit(); + + currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); if (transaction.getVersionedHashes().isPresent()) { currentBlobGasUsed += (transaction.getVersionedHashes().get().size() * CancunGasCalculator.BLOB_GAS_PER_BLOB); @@ -168,7 +179,7 @@ public BlockProcessingResult processBlock( final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( - transaction.getType(), result, worldState, currentGasUsed); + transaction.getType(), transactionProcessingResult, worldState, currentGasUsed); receipts.add(transactionReceipt); } if (blockHeader.getBlobGasUsed().isPresent() @@ -235,6 +246,41 @@ public BlockProcessingResult processBlock( Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests))); } + protected Optional runBlockPreProcessing( + final MutableWorldState worldState, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice) { + return Optional.empty(); + } + + protected TransactionProcessingResult getTransactionProcessingResult( + final Optional preProcessingContext, + final MutableWorldState worldState, + final WorldUpdater blockUpdater, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final Wei blobGasPrice, + final Address miningBeneficiary, + final Transaction transaction, + final int location, + final BlockHashLookup blockHashLookup) { + return transactionProcessor.processTransaction( + blockUpdater, + blockHeader, + transaction, + miningBeneficiary, + OperationTracer.NO_TRACING, + blockHashLookup, + true, + TransactionValidationParams.processingBlock(), + privateMetadataUpdater, + blobGasPrice); + } + protected boolean hasAvailableBlockBudget( final BlockHeader blockHeader, final Transaction transaction, final long currentGasUsed) { final long remainingGasBudget = blockHeader.getGasLimit() - currentGasUsed; @@ -261,4 +307,7 @@ abstract boolean rewardCoinbase( final BlockHeader header, final List ommers, final boolean skipZeroBlockRewards); + + public interface PreprocessingContext {} + ; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index aec844894f7..47c1747dc95 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Collections; @@ -54,16 +55,23 @@ private ClassicProtocolSpecs() { } public static ProtocolSpecBuilder classicRecoveryInitDefinition( - final EvmConfiguration evmConfiguration) { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockHeaderValidatorBuilder( feeMarket -> MainnetBlockHeaderValidator.createClassicValidator()) .name("ClassicRecoveryInit"); } public static ProtocolSpecBuilder tangerineWhistleDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .isReplayProtectionSupported(true) .gasCalculator(TangerineWhistleGasCalculator::new) .transactionValidatorFactoryBuilder( @@ -74,8 +82,12 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( } public static ProtocolSpecBuilder dieHardDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return tangerineWhistleDefinition(chainId, evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return tangerineWhistleDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(DieHardGasCalculator::new) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED) .name("DieHard"); @@ -84,8 +96,11 @@ public static ProtocolSpecBuilder dieHardDefinition( public static ProtocolSpecBuilder gothamDefinition( final Optional chainId, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return dieHardDefinition(chainId, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return dieHardDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockReward(MAX_BLOCK_REWARD) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_DELAYED) .blockProcessorBuilder( @@ -109,8 +124,15 @@ public static ProtocolSpecBuilder gothamDefinition( public static ProtocolSpecBuilder defuseDifficultyBombDefinition( final Optional chainId, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return gothamDefinition( + chainId, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -123,8 +145,15 @@ public static ProtocolSpecBuilder atlantisDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return gothamDefinition( + chainId, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder(MainnetEVMs::byzantium) .evmConfiguration(evmConfiguration) .gasCalculator(SpuriousDragonGasCalculator::new) @@ -163,8 +192,16 @@ public static ProtocolSpecBuilder aghartaDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return atlantisDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return atlantisDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder(MainnetEVMs::constantinople) .gasCalculator(PetersburgGasCalculator::new) .evmBuilder(MainnetEVMs::constantinople) @@ -176,8 +213,16 @@ public static ProtocolSpecBuilder phoenixDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return aghartaDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return aghartaDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(IstanbulGasCalculator::new) .evmBuilder( (gasCalculator, evmConfig) -> @@ -191,8 +236,16 @@ public static ProtocolSpecBuilder thanosDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return phoenixDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return phoenixDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .blockHeaderValidatorBuilder( feeMarket -> MainnetBlockHeaderValidator.createPgaBlockHeaderValidator( @@ -228,8 +281,16 @@ public static ProtocolSpecBuilder magnetoDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return thanosDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return thanosDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -250,8 +311,16 @@ public static ProtocolSpecBuilder mystiqueDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return magnetoDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return magnetoDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(LondonGasCalculator::new) .contractCreationProcessorBuilder( evm -> @@ -264,8 +333,16 @@ public static ProtocolSpecBuilder spiralDefinition( final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return mystiqueDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return mystiqueDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) // EIP-3860 .gasCalculator(ShanghaiGasCalculator::new) // EIP-3855 diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java index 794f96cfb39..88b6a5ae1be 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyCalculators; import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.function.Function; @@ -40,6 +41,8 @@ public class MainnetProtocolSchedule { * @param evmConfiguration how to configure the EVMs jumpdest cache * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to expose metrics in the underlying calls * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( @@ -48,7 +51,9 @@ public static ProtocolSchedule fromConfig( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { if (FixedDifficultyCalculators.isFixedDifficultyInConfig(config)) { return FixedDifficultyProtocolSchedule.create( config, @@ -56,7 +61,9 @@ public static ProtocolSchedule fromConfig( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } return new ProtocolScheduleBuilder( config, @@ -66,7 +73,9 @@ public static ProtocolSchedule fromConfig( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -79,6 +88,7 @@ public static ProtocolSchedule fromConfig( * @param evmConfiguration how to configure the EVMs jumpdest cache * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( @@ -86,14 +96,18 @@ public static ProtocolSchedule fromConfig( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -104,20 +118,25 @@ public static ProtocolSchedule fromConfig( * @param evmConfiguration size of * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, false, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -127,18 +146,23 @@ public static ProtocolSchedule fromConfig( * starting points * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java index aa9bae6c7e3..55bfb363baa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -29,118 +30,209 @@ public class MainnetProtocolSpecFactory { private final OptionalLong ecip1017EraRounds; private final EvmConfiguration evmConfiguration; private final MiningParameters miningParameters; + private final boolean isParallelTxProcessingEnabled; + private final MetricsSystem metricsSystem; public MainnetProtocolSpecFactory( final Optional chainId, final boolean isRevertReasonEnabled, final OptionalLong ecip1017EraRounds, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this.chainId = chainId; this.isRevertReasonEnabled = isRevertReasonEnabled; this.ecip1017EraRounds = ecip1017EraRounds; this.evmConfiguration = evmConfiguration; this.miningParameters = miningParameters; + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + this.metricsSystem = metricsSystem; } public ProtocolSpecBuilder frontierDefinition() { - return MainnetProtocolSpecs.frontierDefinition(evmConfiguration); + return MainnetProtocolSpecs.frontierDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder homesteadDefinition() { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration); + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder daoRecoveryInitDefinition() { - return MainnetProtocolSpecs.daoRecoveryInitDefinition(evmConfiguration); + return MainnetProtocolSpecs.daoRecoveryInitDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder daoRecoveryTransitionDefinition() { - return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(evmConfiguration); + return MainnetProtocolSpecs.daoRecoveryTransitionDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder tangerineWhistleDefinition() { - return MainnetProtocolSpecs.tangerineWhistleDefinition(evmConfiguration); + return MainnetProtocolSpecs.tangerineWhistleDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder spuriousDragonDefinition() { - return MainnetProtocolSpecs.spuriousDragonDefinition(chainId, evmConfiguration); + return MainnetProtocolSpecs.spuriousDragonDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder byzantiumDefinition() { return MainnetProtocolSpecs.byzantiumDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder constantinopleDefinition() { return MainnetProtocolSpecs.constantinopleDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder petersburgDefinition() { return MainnetProtocolSpecs.petersburgDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder istanbulDefinition() { return MainnetProtocolSpecs.istanbulDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder muirGlacierDefinition() { return MainnetProtocolSpecs.muirGlacierDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder berlinDefinition() { - return MainnetProtocolSpecs.berlinDefinition(chainId, isRevertReasonEnabled, evmConfiguration); + return MainnetProtocolSpecs.berlinDefinition( + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder londonDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.londonDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder arrowGlacierDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.arrowGlacierDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder grayGlacierDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.grayGlacierDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder parisDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.parisDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder shanghaiDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.shanghaiDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder cancunDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.cancunDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder cancunEOFDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.cancunEOFDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder pragueDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.pragueDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.pragueEOFDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -156,7 +248,13 @@ public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesi */ public ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.futureEipsDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -172,57 +270,100 @@ public ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genes public ProtocolSpecBuilder experimentalEipsDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.experimentalEipsDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Classic Protocol Specs public ProtocolSpecBuilder dieHardDefinition() { - return ClassicProtocolSpecs.dieHardDefinition(chainId, evmConfiguration); + return ClassicProtocolSpecs.dieHardDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder gothamDefinition() { - return ClassicProtocolSpecs.gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration); + return ClassicProtocolSpecs.gothamDefinition( + chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder defuseDifficultyBombDefinition() { return ClassicProtocolSpecs.defuseDifficultyBombDefinition( - chainId, ecip1017EraRounds, evmConfiguration); + chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder atlantisDefinition() { return ClassicProtocolSpecs.atlantisDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder aghartaDefinition() { return ClassicProtocolSpecs.aghartaDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder phoenixDefinition() { return ClassicProtocolSpecs.phoenixDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder thanosDefinition() { return ClassicProtocolSpecs.thanosDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder magnetoDefinition() { return ClassicProtocolSpecs.magnetoDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder mystiqueDefinition() { return ClassicProtocolSpecs.mystiqueDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder spiralDefinition() { return ClassicProtocolSpecs.spiralDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 6f09df923eb..36d8257ffb9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.blockhash.PragueBlockHashProcessor; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; @@ -67,6 +68,7 @@ import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.io.IOException; import java.math.BigInteger; @@ -101,7 +103,10 @@ public abstract class MainnetProtocolSpecs { private MainnetProtocolSpecs() {} - public static ProtocolSpecBuilder frontierDefinition(final EvmConfiguration evmConfiguration) { + public static ProtocolSpecBuilder frontierDefinition( + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new ProtocolSpecBuilder() .gasCalculator(FrontierGasCalculator::new) .gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator()) @@ -152,7 +157,10 @@ public static ProtocolSpecBuilder frontierDefinition(final EvmConfiguration evmC .transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory) .blockReward(FRONTIER_BLOCK_REWARD) .skipZeroBlockRewards(false) - .blockProcessorBuilder(MainnetBlockProcessor::new) + .blockProcessorBuilder( + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem) + : MainnetBlockProcessor::new) .blockValidatorBuilder(MainnetProtocolSpecs.blockValidatorBuilder()) .blockImporterBuilder(MainnetBlockImporter::new) .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) @@ -173,8 +181,11 @@ public static BlockValidatorBuilder blockValidatorBuilder() { return MainnetBlockValidator::new; } - public static ProtocolSpecBuilder homesteadDefinition(final EvmConfiguration evmConfiguration) { - return frontierDefinition(evmConfiguration) + public static ProtocolSpecBuilder homesteadDefinition( + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return frontierDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(HomesteadGasCalculator::new) .evmBuilder(MainnetEVMs::homestead) .contractCreationProcessorBuilder( @@ -190,8 +201,10 @@ public static ProtocolSpecBuilder homesteadDefinition(final EvmConfiguration evm } public static ProtocolSpecBuilder daoRecoveryInitDefinition( - final EvmConfiguration evmConfiguration) { - return homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.createDaoValidator()) .blockProcessorBuilder( (transactionProcessor, @@ -201,33 +214,53 @@ public static ProtocolSpecBuilder daoRecoveryInitDefinition( skipZeroBlockRewards, protocolSchedule) -> new DaoBlockProcessor( - new MainnetBlockProcessor( - transactionProcessor, - transactionReceiptFactory, - blockReward, - miningBeneficiaryCalculator, - skipZeroBlockRewards, - protocolSchedule))) + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule, + metricsSystem) + : new MainnetBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule))) .name("DaoRecoveryInit"); } public static ProtocolSpecBuilder daoRecoveryTransitionDefinition( - final EvmConfiguration evmConfiguration) { - return daoRecoveryInitDefinition(evmConfiguration) - .blockProcessorBuilder(MainnetBlockProcessor::new) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return daoRecoveryInitDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) + .blockProcessorBuilder( + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem) + : MainnetBlockProcessor::new) .name("DaoRecoveryTransition"); } public static ProtocolSpecBuilder tangerineWhistleDefinition( - final EvmConfiguration evmConfiguration) { - return homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(TangerineWhistleGasCalculator::new) .name("TangerineWhistle"); } public static ProtocolSpecBuilder spuriousDragonDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return tangerineWhistleDefinition(evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return tangerineWhistleDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .isReplayProtectionSupported(true) .gasCalculator(SpuriousDragonGasCalculator::new) .skipZeroBlockRewards(true) @@ -271,8 +304,11 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( public static ProtocolSpecBuilder byzantiumDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return spuriousDragonDefinition(chainId, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return spuriousDragonDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(ByzantiumGasCalculator::new) .evmBuilder(MainnetEVMs::byzantium) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium) @@ -301,8 +337,15 @@ public static ProtocolSpecBuilder byzantiumDefinition( public static ProtocolSpecBuilder constantinopleDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return byzantiumDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return byzantiumDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE) .gasCalculator(ConstantinopleGasCalculator::new) .evmBuilder(MainnetEVMs::constantinople) @@ -313,8 +356,15 @@ public static ProtocolSpecBuilder constantinopleDefinition( public static ProtocolSpecBuilder petersburgDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return constantinopleDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return constantinopleDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(PetersburgGasCalculator::new) .name("Petersburg"); } @@ -322,8 +372,15 @@ public static ProtocolSpecBuilder petersburgDefinition( public static ProtocolSpecBuilder istanbulDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return petersburgDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return petersburgDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(IstanbulGasCalculator::new) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -344,8 +401,15 @@ public static ProtocolSpecBuilder istanbulDefinition( static ProtocolSpecBuilder muirGlacierDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return istanbulDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return istanbulDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.MUIR_GLACIER) .name("MuirGlacier"); } @@ -353,8 +417,15 @@ static ProtocolSpecBuilder muirGlacierDefinition( static ProtocolSpecBuilder berlinDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return muirGlacierDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return muirGlacierDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -376,7 +447,9 @@ static ProtocolSpecBuilder londonDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(Long.MAX_VALUE); final BaseFeeMarket londonFeeMarket; @@ -390,7 +463,12 @@ static ProtocolSpecBuilder londonDefinition( londonFeeMarket = FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); } - return berlinDefinition(chainId, enableRevertReason, evmConfiguration) + return berlinDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .feeMarket(londonFeeMarket) .gasCalculator(LondonGasCalculator::new) .gasLimitCalculatorBuilder( @@ -455,9 +533,17 @@ static ProtocolSpecBuilder arrowGlacierDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return londonDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.ARROW_GLACIER) .name("ArrowGlacier"); } @@ -467,9 +553,17 @@ static ProtocolSpecBuilder grayGlacierDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return arrowGlacierDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.GRAY_GLACIER) .name("GrayGlacier"); } @@ -479,10 +573,18 @@ static ProtocolSpecBuilder parisDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return grayGlacierDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder( (gasCalculator, jdCacheConfig) -> MainnetEVMs.paris(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) @@ -499,9 +601,17 @@ static ProtocolSpecBuilder shanghaiDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return parisDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) // gas calculator has new code to support EIP-3860 limit and meter initcode .gasCalculator(ShanghaiGasCalculator::new) // EVM has a new operation for EIP-3855 PUSH0 instruction @@ -550,7 +660,9 @@ static ProtocolSpecBuilder cancunDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket cancunFeeMarket; if (genesisConfigOptions.isZeroBaseFee()) { @@ -565,7 +677,13 @@ static ProtocolSpecBuilder cancunDefinition( } return shanghaiDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .feeMarket(cancunFeeMarket) // gas calculator for EIP-4844 blob gas .gasCalculator(CancunGasCalculator::new) @@ -623,11 +741,19 @@ static ProtocolSpecBuilder cancunEOFDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSpecBuilder protocolSpecBuilder = cancunDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("CancunEOF"); } @@ -636,14 +762,22 @@ static ProtocolSpecBuilder pragueDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final Address depositContractAddress = genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS); return cancunDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) - // EIP-3074 AUTH and AUTHCALL gas + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) + // EIP-3074 AUTH and AUTCALL gas .gasCalculator(PragueGasCalculator::new) // EIP-3074 AUTH and AUTHCALL .evmBuilder( @@ -686,11 +820,19 @@ static ProtocolSpecBuilder pragueEOFDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSpecBuilder protocolSpecBuilder = pragueDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("PragueEOF"); } @@ -722,9 +864,17 @@ static ProtocolSpecBuilder futureEipsDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return pragueEOFDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) // Use Future EIP configured EVM .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -749,10 +899,18 @@ static ProtocolSpecBuilder experimentalEipsDefinition( final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return futureEipsDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder( (gasCalculator, jdCacheConfig) -> MainnetEVMs.experimentalEips( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 9ad1db7d896..5fa2b119f1c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -507,7 +507,6 @@ public TransactionProcessingResult processTransaction( final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); // update the coinbase - final var coinbase = worldState.getOrCreate(miningBeneficiary); final long usedGas = transaction.getGasLimit() - refundedGas; final CoinbaseFeePriceCalculator coinbaseCalculator; if (blockHeader.getBaseFee().isPresent()) { @@ -529,6 +528,9 @@ public TransactionProcessingResult processTransaction( final Wei coinbaseWeiDelta = coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee()); + operationTracer.traceBeforeRewardTransaction(worldUpdater, transaction, coinbaseWeiDelta); + + final var coinbase = worldState.getOrCreate(miningBeneficiary); coinbase.incrementBalance(coinbaseWeiDelta); authorizedCodeService.resetAuthorities(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index 649442f88c1..1cb3a5cb3c5 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.NavigableMap; @@ -45,6 +46,8 @@ public class ProtocolScheduleBuilder { private final EvmConfiguration evmConfiguration; private final MiningParameters miningParameters; private final BadBlockManager badBlockManager; + private final boolean isParallelTxProcessingEnabled; + private final MetricsSystem metricsSystem; public ProtocolScheduleBuilder( final GenesisConfigOptions config, @@ -54,7 +57,9 @@ public ProtocolScheduleBuilder( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this( config, Optional.of(defaultChainId), @@ -63,7 +68,9 @@ public ProtocolScheduleBuilder( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolScheduleBuilder( @@ -73,7 +80,9 @@ public ProtocolScheduleBuilder( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this( config, Optional.empty(), @@ -82,7 +91,9 @@ public ProtocolScheduleBuilder( isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } private ProtocolScheduleBuilder( @@ -93,7 +104,9 @@ private ProtocolScheduleBuilder( final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this.config = config; this.protocolSpecAdapters = protocolSpecAdapters; this.privacyParameters = privacyParameters; @@ -102,6 +115,8 @@ private ProtocolScheduleBuilder( this.defaultChainId = defaultChainId; this.miningParameters = miningParameters; this.badBlockManager = badBlockManager; + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + this.metricsSystem = metricsSystem; } public ProtocolSchedule createProtocolSchedule() { @@ -121,7 +136,9 @@ private void initSchedule( config.getEcip1017EraRounds(), evmConfiguration.overrides( config.getContractSizeLimit(), OptionalInt.empty(), config.getEvmStackSize()), - miningParameters); + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); validateForkOrdering(); @@ -203,7 +220,8 @@ private void initSchedule( protocolSchedule, BuilderMapEntry.MilestoneType.BLOCK_NUMBER, classicBlockNumber, - ClassicProtocolSpecs.classicRecoveryInitDefinition(evmConfiguration), + ClassicProtocolSpecs.classicRecoveryInitDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem), Function.identity()); protocolSchedule.putBlockNumberMilestone( classicBlockNumber + 1, originalProtocolSpec); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index cd886b6c847..0d792b7870c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -51,6 +51,7 @@ public class ProtocolSpecBuilder { private Function gasLimitCalculatorBuilder; private Wei blockReward; private boolean skipZeroBlockRewards; + private BlockHeaderFunctions blockHeaderFunctions; private AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private DifficultyCalculator difficultyCalculator; @@ -66,9 +67,11 @@ public class ProtocolSpecBuilder { private BiFunction messageCallProcessorBuilder; private TransactionProcessorBuilder transactionProcessorBuilder; + private BlockProcessorBuilder blockProcessorBuilder; private BlockValidatorBuilder blockValidatorBuilder; private BlockImporterBuilder blockImporterBuilder; + private String name; private MiningBeneficiaryCalculator miningBeneficiaryCalculator; private PrivacyParameters privacyParameters; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java new file mode 100644 index 00000000000..d1f0d9c5127 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java @@ -0,0 +1,199 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.evm.operation.BlockHashOperation; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.metrics.Counter; + +import java.util.List; +import java.util.Optional; + +public class MainnetParallelBlockProcessor extends MainnetBlockProcessor { + + private final Optional metricsSystem; + private final Optional confirmedParallelizedTransactionCounter; + private final Optional conflictingButCachedTransactionCounter; + + public MainnetParallelBlockProcessor( + final MainnetTransactionProcessor transactionProcessor, + final TransactionReceiptFactory transactionReceiptFactory, + final Wei blockReward, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator, + final boolean skipZeroBlockRewards, + final ProtocolSchedule protocolSchedule, + final MetricsSystem metricsSystem) { + super( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule); + this.metricsSystem = Optional.of(metricsSystem); + this.confirmedParallelizedTransactionCounter = + Optional.of( + this.metricsSystem + .get() + .createCounter( + BesuMetricCategory.BLOCK_PROCESSING, + "parallelized_transactions_counter", + "Counter for the number of parallelized transactions during block processing")); + + this.conflictingButCachedTransactionCounter = + Optional.of( + this.metricsSystem + .get() + .createCounter( + BesuMetricCategory.BLOCK_PROCESSING, + "conflicted_transactions_counter", + "Counter for the number of conflicted transactions during block processing")); + } + + @Override + protected Optional runBlockPreProcessing( + final MutableWorldState worldState, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice) { + if ((worldState instanceof DiffBasedWorldState)) { + ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor = + new ParallelizedConcurrentTransactionProcessor(transactionProcessor); + // runAsyncBlock, if activated, facilitates the non-blocking parallel execution of + // transactions in the background through an optimistic strategy. + parallelizedConcurrentTransactionProcessor.runAsyncBlock( + worldState, + blockHeader, + transactions, + miningBeneficiary, + blockHashLookup, + blobGasPrice, + privateMetadataUpdater); + return Optional.of( + new ParallelizedPreProcessingContext(parallelizedConcurrentTransactionProcessor)); + } + return Optional.empty(); + } + + @Override + protected TransactionProcessingResult getTransactionProcessingResult( + final Optional preProcessingContext, + final MutableWorldState worldState, + final WorldUpdater blockUpdater, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final Wei blobGasPrice, + final Address miningBeneficiary, + final Transaction transaction, + final int location, + final BlockHashOperation.BlockHashLookup blockHashLookup) { + + TransactionProcessingResult transactionProcessingResult = null; + + if (preProcessingContext.isPresent()) { + final ParallelizedPreProcessingContext parallelizedPreProcessingContext = + (ParallelizedPreProcessingContext) preProcessingContext.get(); + transactionProcessingResult = + parallelizedPreProcessingContext + .getParallelizedConcurrentTransactionProcessor() + .applyParallelizedTransactionResult( + worldState, + miningBeneficiary, + transaction, + location, + confirmedParallelizedTransactionCounter, + conflictingButCachedTransactionCounter) + .orElse(null); + } + + if (transactionProcessingResult == null) { + return super.getTransactionProcessingResult( + preProcessingContext, + worldState, + blockUpdater, + privateMetadataUpdater, + blockHeader, + blobGasPrice, + miningBeneficiary, + transaction, + location, + blockHashLookup); + } else { + return transactionProcessingResult; + } + } + + static class ParallelizedPreProcessingContext implements PreprocessingContext { + final ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor; + + public ParallelizedPreProcessingContext( + final ParallelizedConcurrentTransactionProcessor + parallelizedConcurrentTransactionProcessor) { + this.parallelizedConcurrentTransactionProcessor = parallelizedConcurrentTransactionProcessor; + } + + public ParallelizedConcurrentTransactionProcessor + getParallelizedConcurrentTransactionProcessor() { + return parallelizedConcurrentTransactionProcessor; + } + } + + public static class ParallelBlockProcessorBuilder + implements ProtocolSpecBuilder.BlockProcessorBuilder { + + final MetricsSystem metricsSystem; + + public ParallelBlockProcessorBuilder(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + } + + @Override + public BlockProcessor apply( + final MainnetTransactionProcessor transactionProcessor, + final TransactionReceiptFactory transactionReceiptFactory, + final Wei blockReward, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator, + final boolean skipZeroBlockRewards, + final ProtocolSchedule protocolSchedule) { + return new MainnetParallelBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule, + metricsSystem); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java new file mode 100644 index 00000000000..c6beaa2f40e --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java @@ -0,0 +1,268 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoopBonsaiCachedMerkleTrieLoader; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; +import org.hyperledger.besu.evm.operation.BlockHashOperation; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.WorldView; +import org.hyperledger.besu.plugin.services.metrics.Counter; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Optimizes transaction processing by executing transactions in parallel within a given block. + * Transactions are executed optimistically in a non-blocking manner. After execution, the class + * checks for potential conflicts among transactions to ensure data integrity before applying the + * results to the world state. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class ParallelizedConcurrentTransactionProcessor { + + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + private static final Executor executor = Executors.newFixedThreadPool(NCPU); + + private final MainnetTransactionProcessor transactionProcessor; + + private final TransactionCollisionDetector transactionCollisionDetector; + + private final Map + parallelizedTransactionContextByLocation = new ConcurrentHashMap<>(); + + /** + * Constructs a PreloadConcurrentTransactionProcessor with a specified transaction processor. This + * processor is responsible for the individual processing of transactions. + * + * @param transactionProcessor The transaction processor for processing individual transactions. + */ + public ParallelizedConcurrentTransactionProcessor( + final MainnetTransactionProcessor transactionProcessor) { + this.transactionProcessor = transactionProcessor; + this.transactionCollisionDetector = new TransactionCollisionDetector(); + } + + @VisibleForTesting + public ParallelizedConcurrentTransactionProcessor( + final MainnetTransactionProcessor transactionProcessor, + final TransactionCollisionDetector transactionCollisionDetector) { + this.transactionProcessor = transactionProcessor; + this.transactionCollisionDetector = transactionCollisionDetector; + } + + /** + * Initiates the parallel and optimistic execution of transactions within a block by creating a + * copy of the world state for each transaction. This method processes transactions in a + * non-blocking manner. Transactions are executed against their respective copies of the world + * state, ensuring that the original world state passed as a parameter remains unmodified during + * this process. + * + * @param worldState Mutable world state intended for applying transaction results. This world + * state is not modified directly; instead, copies are made for transaction execution. + * @param blockHeader Header of the current block containing the transactions. + * @param transactions List of transactions to be processed. + * @param miningBeneficiary Address of the beneficiary to receive mining rewards. + * @param blockHashLookup Function for block hash lookup. + * @param blobGasPrice Gas price for blob transactions. + * @param privateMetadataUpdater Updater for private transaction metadata. + */ + public void runAsyncBlock( + final MutableWorldState worldState, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice, + final PrivateMetadataUpdater privateMetadataUpdater) { + for (int i = 0; i < transactions.size(); i++) { + final Transaction transaction = transactions.get(i); + final int transactionLocation = i; + /* + * All transactions are executed in the background by copying the world state of the block on which the transactions need to be executed, ensuring that each one has its own accumulator. + */ + CompletableFuture.runAsync( + () -> + runTransaction( + worldState, + blockHeader, + transactionLocation, + transaction, + miningBeneficiary, + blockHashLookup, + blobGasPrice, + privateMetadataUpdater), + executor); + } + } + + @VisibleForTesting + public void runTransaction( + final MutableWorldState worldState, + final BlockHeader blockHeader, + final int transactionLocation, + final Transaction transaction, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice, + final PrivateMetadataUpdater privateMetadataUpdater) { + try (final DiffBasedWorldState roundWorldState = + new BonsaiWorldState( + (BonsaiWorldState) worldState, new NoopBonsaiCachedMerkleTrieLoader())) { + roundWorldState.freeze(); // make the clone frozen + final ParallelizedTransactionContext.Builder contextBuilder = + new ParallelizedTransactionContext.Builder(); + final DiffBasedWorldStateUpdateAccumulator roundWorldStateUpdater = + (DiffBasedWorldStateUpdateAccumulator) roundWorldState.updater(); + final TransactionProcessingResult result = + transactionProcessor.processTransaction( + roundWorldStateUpdater, + blockHeader, + transaction, + miningBeneficiary, + new OperationTracer() { + @Override + public void traceBeforeRewardTransaction( + final WorldView worldView, + final org.hyperledger.besu.datatypes.Transaction tx, + final Wei miningReward) { + /* + * This part checks if the mining beneficiary's account was accessed before increasing its balance for rewards. + * Indeed, if the transaction has interacted with the address to read or modify it, + * it means that the value is necessary for the proper execution of the transaction and will therefore be considered in collision detection. + * If this is not the case, we can ignore this address during conflict detection. + */ + if (transactionCollisionDetector + .getAddressesTouchedByTransaction( + transaction, Optional.of(roundWorldStateUpdater)) + .contains(miningBeneficiary)) { + contextBuilder.isMiningBeneficiaryTouchedPreRewardByTransaction(true); + } + contextBuilder.miningBeneficiaryReward(miningReward); + } + }, + blockHashLookup, + true, + TransactionValidationParams.processingBlock(), + privateMetadataUpdater, + blobGasPrice); + + // commit the accumulator in order to apply all the modifications + roundWorldState.getAccumulator().commit(); + + contextBuilder + .transactionAccumulator(roundWorldState.getAccumulator()) + .transactionProcessingResult(result); + + final ParallelizedTransactionContext parallelizedTransactionContext = contextBuilder.build(); + if (!parallelizedTransactionContext.isMiningBeneficiaryTouchedPreRewardByTransaction()) { + /* + * If the address of the mining beneficiary has been touched only for adding rewards, + * we remove it from the accumulator to avoid a false positive collision. + * The balance will be increased during the sequential processing. + */ + roundWorldStateUpdater.getAccountsToUpdate().remove(miningBeneficiary); + } + parallelizedTransactionContextByLocation.put( + transactionLocation, parallelizedTransactionContext); + } + } + + /** + * Applies the results of parallelized transactions to the world state after checking for + * conflicts. + * + *

If a transaction was executed optimistically without any detected conflicts, its result is + * directly applied to the world state. If there is a conflict, this method does not apply the + * transaction's modifications directly to the world state. Instead, it caches the data read from + * the database during the transaction's execution. This cached data is then used to optimize the + * replay of the transaction by reducing the need for additional reads from the disk, thereby + * making the replay process faster. This approach ensures that the integrity of the world state + * is maintained while optimizing the performance of transaction processing. + * + * @param worldState Mutable world state intended for applying transaction results. + * @param miningBeneficiary Address of the beneficiary for mining rewards. + * @param transaction Transaction for which the result is to be applied. + * @param transactionLocation Index of the transaction within the block. + * @param confirmedParallelizedTransactionCounter Metric counter for confirmed parallelized + * transactions + * @param conflictingButCachedTransactionCounter Metric counter for conflicting but cached + * transactions + * @return Optional containing the transaction processing result if applied, or empty if the + * transaction needs to be replayed due to a conflict. + */ + public Optional applyParallelizedTransactionResult( + final MutableWorldState worldState, + final Address miningBeneficiary, + final Transaction transaction, + final int transactionLocation, + final Optional confirmedParallelizedTransactionCounter, + final Optional conflictingButCachedTransactionCounter) { + final DiffBasedWorldState diffBasedWorldState = (DiffBasedWorldState) worldState; + final DiffBasedWorldStateUpdateAccumulator blockAccumulator = + (DiffBasedWorldStateUpdateAccumulator) diffBasedWorldState.updater(); + final ParallelizedTransactionContext parallelizedTransactionContext = + parallelizedTransactionContextByLocation.remove(transactionLocation); + /* + * If `parallelizedTransactionContext` is not null, it means that the transaction had time to complete in the background. + */ + if (parallelizedTransactionContext != null) { + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator = + parallelizedTransactionContext.transactionAccumulator(); + final TransactionProcessingResult transactionProcessingResult = + parallelizedTransactionContext.transactionProcessingResult(); + final boolean hasCollision = + transactionCollisionDetector.hasCollision( + transaction, miningBeneficiary, parallelizedTransactionContext, blockAccumulator); + if (transactionProcessingResult.isSuccessful() && !hasCollision) { + blockAccumulator + .getOrCreate(miningBeneficiary) + .incrementBalance(parallelizedTransactionContext.miningBeneficiaryReward()); + + blockAccumulator.importStateChangesFromSource(transactionAccumulator); + + if (confirmedParallelizedTransactionCounter.isPresent()) + confirmedParallelizedTransactionCounter.get().inc(); + return Optional.of(transactionProcessingResult); + } else { + blockAccumulator.importPriorStateFromSource(transactionAccumulator); + if (conflictingButCachedTransactionCounter.isPresent()) + conflictingButCachedTransactionCounter.get().inc(); + // If there is a conflict, we return an empty result to signal the block processor to + // re-execute the transaction. + return Optional.empty(); + } + } + return Optional.empty(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java new file mode 100644 index 00000000000..30305ce00b5 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java @@ -0,0 +1,133 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; + +import java.util.Objects; + +public final class ParallelizedTransactionContext { + private final DiffBasedWorldStateUpdateAccumulator transactionAccumulator; + private final TransactionProcessingResult transactionProcessingResult; + private final boolean isMiningBeneficiaryTouchedPreRewardByTransaction; + private final Wei miningBeneficiaryReward; + + public ParallelizedTransactionContext( + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator, + final TransactionProcessingResult transactionProcessingResult, + final boolean isMiningBeneficiaryTouchedPreRewardByTransaction, + final Wei miningBeneficiaryReward) { + this.transactionAccumulator = transactionAccumulator; + this.transactionProcessingResult = transactionProcessingResult; + this.isMiningBeneficiaryTouchedPreRewardByTransaction = + isMiningBeneficiaryTouchedPreRewardByTransaction; + this.miningBeneficiaryReward = miningBeneficiaryReward; + } + + public DiffBasedWorldStateUpdateAccumulator transactionAccumulator() { + return transactionAccumulator; + } + + public TransactionProcessingResult transactionProcessingResult() { + return transactionProcessingResult; + } + + public boolean isMiningBeneficiaryTouchedPreRewardByTransaction() { + return isMiningBeneficiaryTouchedPreRewardByTransaction; + } + + public Wei miningBeneficiaryReward() { + return miningBeneficiaryReward; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (ParallelizedTransactionContext) obj; + return Objects.equals(this.transactionAccumulator, that.transactionAccumulator) + && Objects.equals(this.transactionProcessingResult, that.transactionProcessingResult) + && this.isMiningBeneficiaryTouchedPreRewardByTransaction + == that.isMiningBeneficiaryTouchedPreRewardByTransaction + && Objects.equals(this.miningBeneficiaryReward, that.miningBeneficiaryReward); + } + + @Override + public int hashCode() { + return Objects.hash( + transactionAccumulator, + transactionProcessingResult, + isMiningBeneficiaryTouchedPreRewardByTransaction, + miningBeneficiaryReward); + } + + @Override + public String toString() { + return "ParallelizedTransactionContext[" + + "transactionAccumulator=" + + transactionAccumulator + + ", " + + "transactionProcessingResult=" + + transactionProcessingResult + + ", " + + "isMiningBeneficiaryTouchedPreRewardByTransaction=" + + isMiningBeneficiaryTouchedPreRewardByTransaction + + ", " + + "miningBeneficiaryReward=" + + miningBeneficiaryReward + + ']'; + } + + public static class Builder { + private DiffBasedWorldStateUpdateAccumulator transactionAccumulator; + private TransactionProcessingResult transactionProcessingResult; + private boolean isMiningBeneficiaryTouchedPreRewardByTransaction; + private Wei miningBeneficiaryReward = Wei.ZERO; + + public Builder transactionAccumulator( + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator) { + this.transactionAccumulator = transactionAccumulator; + return this; + } + + public Builder transactionProcessingResult( + final TransactionProcessingResult transactionProcessingResult) { + this.transactionProcessingResult = transactionProcessingResult; + return this; + } + + public Builder isMiningBeneficiaryTouchedPreRewardByTransaction( + final boolean isMiningBeneficiaryTouchedPreRewardByTransaction) { + this.isMiningBeneficiaryTouchedPreRewardByTransaction = + isMiningBeneficiaryTouchedPreRewardByTransaction; + return this; + } + + public Builder miningBeneficiaryReward(final Wei miningBeneficiaryReward) { + this.miningBeneficiaryReward = miningBeneficiaryReward; + return this; + } + + public ParallelizedTransactionContext build() { + return new ParallelizedTransactionContext( + transactionAccumulator, + transactionProcessingResult, + isMiningBeneficiaryTouchedPreRewardByTransaction, + miningBeneficiaryReward); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java new file mode 100644 index 00000000000..4120c0edb1e --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java @@ -0,0 +1,114 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; + +public class TransactionCollisionDetector { + + /** + * Determines if a transaction has a collision based on the addresses it touches. A collision + * occurs if the transaction touches the mining beneficiary address or if there are common + * addresses touched by both the transaction and other transactions within the same block. + * + * @param transaction The transaction to check for collisions. + * @param miningBeneficiary The address of the mining beneficiary. + * @param parallelizedTransactionContext The context containing the accumulator for the + * transaction. + * @param blockAccumulator The accumulator for the block. + * @return true if there is a collision; false otherwise. + */ + public boolean hasCollision( + final Transaction transaction, + final Address miningBeneficiary, + final ParallelizedTransactionContext parallelizedTransactionContext, + final DiffBasedWorldStateUpdateAccumulator blockAccumulator) { + final Set

addressesTouchedByTransaction = + getAddressesTouchedByTransaction( + transaction, Optional.of(parallelizedTransactionContext.transactionAccumulator())); + if (addressesTouchedByTransaction.contains(miningBeneficiary)) { + return true; + } + final Set
addressesTouchedByBlock = + getAddressesTouchedByBlock(Optional.of(blockAccumulator)); + final Iterator
it = addressesTouchedByTransaction.iterator(); + boolean commonAddressFound = false; + while (it.hasNext() && !commonAddressFound) { + if (addressesTouchedByBlock.contains(it.next())) { + commonAddressFound = true; + } + } + return commonAddressFound; + } + + /** + * Retrieves the set of addresses that were touched by a transaction. This includes the sender and + * recipient of the transaction, as well as any addresses that were read from or written to by the + * transaction's execution. + * + * @param transaction The transaction to analyze. + * @param accumulator An optional accumulator containing state changes made by the transaction. + * @return A set of addresses touched by the transaction. + */ + public Set
getAddressesTouchedByTransaction( + final Transaction transaction, + final Optional> accumulator) { + HashSet
addresses = new HashSet<>(); + addresses.add(transaction.getSender()); + if (transaction.getTo().isPresent()) { + addresses.add(transaction.getTo().get()); + } + accumulator.ifPresent( + diffBasedWorldStateUpdateAccumulator -> { + diffBasedWorldStateUpdateAccumulator + .getAccountsToUpdate() + .forEach((address, diffBasedValue) -> addresses.add(address)); + addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses()); + }); + return addresses; + } + + /** + * Retrieves the set of addresses that were touched by all transactions within a block. This + * method filters out addresses that were only read and not modified. + * + * @param accumulator An optional accumulator containing state changes made by the block. + * @return A set of addresses that were modified by the block's transactions. + */ + private Set
getAddressesTouchedByBlock( + final Optional> accumulator) { + HashSet
addresses = new HashSet<>(); + accumulator.ifPresent( + diffBasedWorldStateUpdateAccumulator -> { + diffBasedWorldStateUpdateAccumulator + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + if (!diffBasedValue.isUnchanged()) { + addresses.add(address); + } + }); + addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses()); + }); + return addresses; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java new file mode 100644 index 00000000000..8f58e697fee --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java @@ -0,0 +1,44 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.trie.diffbased.bonsai.cache; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.StorageSlotKey; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; + +public class NoopBonsaiCachedMerkleTrieLoader extends BonsaiCachedMerkleTrieLoader { + + public NoopBonsaiCachedMerkleTrieLoader() { + super(new NoOpMetricsSystem()); + } + + @Override + public void preLoadAccount( + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, + final Hash worldStateRootHash, + final Address account) { + // noop + } + + @Override + public void preLoadStorageSlot( + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, + final Address account, + final StorageSlotKey slotKey) { + // noop + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java index ad838aa528d..b62805c1fda 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java @@ -76,6 +76,18 @@ public BonsaiWorldState( diffBasedWorldStateConfig); } + public BonsaiWorldState( + final BonsaiWorldState worldState, + final BonsaiCachedMerkleTrieLoader cachedMerkleTrieLoader) { + this( + new BonsaiWorldStateLayerStorage(worldState.getWorldStateStorage()), + cachedMerkleTrieLoader, + worldState.cachedWorldStorageManager, + worldState.trieLogManager, + worldState.accumulator.getEvmConfiguration(), + new DiffBasedWorldStateConfig(worldState.worldStateConfig)); + } + public BonsaiWorldState( final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java index b5bae0aed9b..0799ed3db27 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java @@ -90,7 +90,7 @@ public DiffBasedWorldStateUpdateAccumulator( this.evmConfiguration = evmConfiguration; } - protected void cloneFromUpdater(final DiffBasedWorldStateUpdateAccumulator source) { + public void cloneFromUpdater(final DiffBasedWorldStateUpdateAccumulator source) { accountsToUpdate.putAll(source.getAccountsToUpdate()); codeToUpdate.putAll(source.codeToUpdate); storageToClear.addAll(source.storageToClear); @@ -100,6 +100,120 @@ protected void cloneFromUpdater(final DiffBasedWorldStateUpdateAccumulator source) { + source + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + ACCOUNT copyPrior = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, false) + : null; + ACCOUNT copyUpdated = + diffBasedValue.getUpdated() != null + ? copyAccount(diffBasedValue.getUpdated(), this, true) + : null; + accountsToUpdate.put(address, new DiffBasedValue<>(copyPrior, copyUpdated)); + }); + source + .getCodeToUpdate() + .forEach( + (address, diffBasedValue) -> { + codeToUpdate.put( + address, + new DiffBasedValue<>(diffBasedValue.getPrior(), diffBasedValue.getUpdated())); + }); + source + .getStorageToUpdate() + .forEach( + (address, slots) -> { + StorageConsumingMap> storageConsumingMap = + storageToUpdate.computeIfAbsent( + address, + k -> + new StorageConsumingMap<>( + address, new ConcurrentHashMap<>(), storagePreloader)); + slots.forEach( + (storageSlotKey, uInt256DiffBasedValue) -> { + storageConsumingMap.put( + storageSlotKey, + new DiffBasedValue<>( + uInt256DiffBasedValue.getPrior(), uInt256DiffBasedValue.getUpdated())); + }); + }); + storageToClear.addAll(source.storageToClear); + + this.isAccumulatorStateChanged = true; + } + + /** + * Imports unchanged state data from an external source into the current state. This method + * focuses on integrating state data from the specified source that has been read but not + * modified. + * + *

The method ensures that only new, unmodified data from the source is added to the current + * state. If a state data has already been read or modified in the current state, it will not be + * added again to avoid overwriting any existing modifications. + * + * @param source The source accumulator + */ + public void importPriorStateFromSource( + final DiffBasedWorldStateUpdateAccumulator source) { + + source + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + ACCOUNT copyPrior = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, false) + : null; + ACCOUNT copyUpdated = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, true) + : null; + accountsToUpdate.putIfAbsent(address, new DiffBasedValue<>(copyPrior, copyUpdated)); + }); + source + .getCodeToUpdate() + .forEach( + (address, diffBasedValue) -> { + codeToUpdate.putIfAbsent( + address, + new DiffBasedValue<>(diffBasedValue.getPrior(), diffBasedValue.getPrior())); + }); + source + .getStorageToUpdate() + .forEach( + (address, slots) -> { + StorageConsumingMap> storageConsumingMap = + storageToUpdate.computeIfAbsent( + address, + k -> + new StorageConsumingMap<>( + address, new ConcurrentHashMap<>(), storagePreloader)); + slots.forEach( + (storageSlotKey, uInt256DiffBasedValue) -> { + storageConsumingMap.putIfAbsent( + storageSlotKey, + new DiffBasedValue<>( + uInt256DiffBasedValue.getPrior(), uInt256DiffBasedValue.getPrior())); + }); + }); + this.isAccumulatorStateChanged = true; + } + protected Consumer> getAccountPreloader() { return accountPreloader; } @@ -108,7 +222,7 @@ protected Consumer getStoragePreloader() { return storagePreloader; } - protected EvmConfiguration getEvmConfiguration() { + public EvmConfiguration getEvmConfiguration() { return evmConfiguration; } @@ -234,6 +348,7 @@ public void revert() { @Override public void commit() { this.isAccumulatorStateChanged = true; + for (final Address deletedAddress : getDeletedAccounts()) { final DiffBasedValue accountValue = accountsToUpdate.computeIfAbsent( @@ -305,7 +420,6 @@ public void commit() { final ACCOUNT updatedAccount; final DiffBasedValue updatedAccountValue = accountsToUpdate.get(updatedAddress); - final Map> pendingStorageUpdates = storageToUpdate.computeIfAbsent( updatedAddress, @@ -359,12 +473,6 @@ public void commit() { pendingStorageUpdates.clear(); } - // This is especially to avoid unnecessary computation for withdrawals and - // self-destruct beneficiaries - if (updatedAccount.getUpdatedStorage().isEmpty()) { - return; - } - // parallel stream here may cause database corruption updatedAccount .getUpdatedStorage() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java index 646e67d2da5..615b5bad6eb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/DataStorageConfiguration.java @@ -85,6 +85,8 @@ interface Unstable { boolean DEFAULT_BONSAI_FULL_FLAT_DB_ENABLED = true; boolean DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED = true; + boolean DEFAULT_PARALLEL_TRX_ENABLED = false; + DataStorageConfiguration.Unstable DEFAULT = ImmutableDataStorageConfiguration.Unstable.builder().build(); @@ -100,5 +102,10 @@ default boolean getBonsaiFullFlatDbEnabled() { default boolean getBonsaiCodeStoredByCodeHashEnabled() { return DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED; } + + @Value.Default + default boolean isParallelTxProcessingEnabled() { + return DEFAULT_PARALLEL_TRX_ENABLED; + } } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java index 60b40c5f24b..551f593e825 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockchainSetupUtil.java @@ -142,7 +142,9 @@ private static ProtocolSchedule mainnetProtocolScheduleProvider( genesisConfigFile.getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.newDefault(), - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private static ProtocolContext mainnetProtocolContextProvider( diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java index 5aa00d0ed64..91ab41b636d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java @@ -146,7 +146,9 @@ public ExecutionContextTestFixture build() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } if (blockchainKeyValueStorage == null) { diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java index a4c6556ea34..e94c6b49fd0 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; @@ -39,7 +40,9 @@ public class ProtocolScheduleFixture { false, EvmConfiguration.DEFAULT, MiningParameters.newDefault(), - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private static GenesisConfigOptions getMainnetConfigOptions() { // this method avoids reading all the alloc accounts when all we want is the "config" section diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java index d2d1fed8b73..d3a261803fb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.blockhash.FrontierBlockHashProcessor; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider; @@ -50,6 +51,7 @@ import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -80,6 +82,8 @@ class BlockImportExceptionHandlingTest { private final BlockBodyValidator blockBodyValidator = mock(BlockBodyValidator.class); private final ProtocolContext protocolContext = mock(ProtocolContext.class); private final ProtocolSpec protocolSpec = mock(ProtocolSpec.class); + private final GasCalculator gasCalculator = mock(GasCalculator.class); + private final FeeMarket feeMarket = mock(FeeMarket.class); protected final MutableBlockchain blockchain = mock(MutableBlockchain.class); private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); @@ -116,6 +120,8 @@ public void setup() { when(protocolSpec.getRequestsValidatorCoordinator()) .thenReturn(RequestsValidatorCoordinator.empty()); when(protocolSpec.getBlockHashProcessor()).thenReturn(new FrontierBlockHashProcessor()); + when(protocolSpec.getGasCalculator()).thenReturn(gasCalculator); + when(protocolSpec.getFeeMarket()).thenReturn(feeMarket); mainnetBlockValidator = new MainnetBlockValidator( blockHeaderValidator, blockBodyValidator, blockProcessor, badBlockManager); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java index adaf4c476b2..7969ab6824a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedProtocolScheduleTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.junit.jupiter.api.Test; @@ -36,7 +37,9 @@ public void reportedDifficultyForAllBlocksIsAFixedValue() { GenesisConfigFile.fromResource("/dev.json").getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java index 9e4522912d7..2d5dd2cee34 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -61,7 +62,9 @@ public void setup() { isRevertReasonEnabled, evmConfiguration, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } @Test diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java index fa8cda5cffc..c63a9b5ccbd 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolScheduleTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -73,7 +74,9 @@ public void shouldOnlyUseFrontierWhenEmptyJsonConfigIsUsed() { GenesisConfigFile.fromConfig("{}").getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); Assertions.assertThat(sched.getByBlockHeader(blockHeader(1L)).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockHeader(blockHeader(Long.MAX_VALUE)).getName()) .isEqualTo("Frontier"); @@ -88,7 +91,9 @@ public void createFromConfigWithSettings() { GenesisConfigFile.fromConfig(json).getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); Assertions.assertThat(sched.getByBlockHeader(blockHeader(1)).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockHeader(blockHeader(2)).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockHeader(blockHeader(3)).getName()) @@ -120,7 +125,9 @@ public void outOfOrderConstantinoplesFail() { GenesisConfigFile.fromConfig(json).getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())); + new BadBlockManager(), + false, + new NoOpMetricsSystem())); } private BlockHeader blockHeader(final long number) { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java index c7be26039e3..0e1011de761 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.OptionalLong; @@ -61,7 +62,9 @@ public void setup() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } @Test @@ -216,7 +219,9 @@ private MilestoneStreamingProtocolSchedule createScheduleModifiedAt(final int bl false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); return new MilestoneStreamingProtocolSchedule( (DefaultProtocolSchedule) builder.createProtocolSchedule()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessorTest.java new file mode 100644 index 00000000000..bba91843568 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessorTest.java @@ -0,0 +1,213 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoOpBonsaiCachedWorldStorageManager; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoopBonsaiCachedMerkleTrieLoader; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.NoOpTrieLogManager; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.evm.operation.BlockHashOperation; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; + +import java.util.Collections; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ParallelizedConcurrentTransactionProcessorTest { + + @Mock private MainnetTransactionProcessor transactionProcessor; + @Mock private BlockHeader blockHeader; + @Mock private Transaction transaction; + @Mock private PrivateMetadataUpdater privateMetadataUpdater; + @Mock private TransactionCollisionDetector transactionCollisionDetector; + + private BonsaiWorldState worldState; + + private ParallelizedConcurrentTransactionProcessor processor; + + @BeforeEach + void setUp() { + processor = + new ParallelizedConcurrentTransactionProcessor( + transactionProcessor, transactionCollisionDetector); + final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage = + new BonsaiWorldStateKeyValueStorage( + new InMemoryKeyValueStorageProvider(), + new NoOpMetricsSystem(), + DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + worldState = + new BonsaiWorldState( + bonsaiWorldStateKeyValueStorage, + new NoopBonsaiCachedMerkleTrieLoader(), + new NoOpBonsaiCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage), + new NoOpTrieLogManager(), + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); + when(transactionCollisionDetector.hasCollision(any(), any(), any(), any())).thenReturn(false); + } + + @Test + void testRunTransaction() { + Address miningBeneficiary = Address.fromHexString("0x1"); + Wei blobGasPrice = Wei.ZERO; + + Mockito.when( + transactionProcessor.processTransaction( + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any())) + .thenReturn( + TransactionProcessingResult.successful( + Collections.emptyList(), 0, 0, Bytes.EMPTY, ValidationResult.valid())); + + processor.runTransaction( + worldState, + blockHeader, + 0, + transaction, + miningBeneficiary, + (blockNumber) -> Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + verify(transactionProcessor, times(1)) + .processTransaction( + any(DiffBasedWorldStateUpdateAccumulator.class), + eq(blockHeader), + eq(transaction), + eq(miningBeneficiary), + any(OperationTracer.class), + any(BlockHashOperation.BlockHashLookup.class), + eq(true), + eq(TransactionValidationParams.processingBlock()), + eq(privateMetadataUpdater), + eq(blobGasPrice)); + + assertTrue( + processor + .applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()) + .isPresent(), + "Expected the transaction context to be stored"); + } + + @Test + void testRunTransactionWithFailure() { + Address miningBeneficiary = Address.fromHexString("0x1"); + Wei blobGasPrice = Wei.ZERO; + + when(transactionProcessor.processTransaction( + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any())) + .thenReturn( + TransactionProcessingResult.failed( + 0, + 0, + ValidationResult.invalid( + TransactionInvalidReason.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE), + Optional.of(Bytes.EMPTY))); + + processor.runTransaction( + worldState, + blockHeader, + 0, + transaction, + miningBeneficiary, + (blockNumber) -> Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + Optional result = + processor.applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()); + assertTrue(result.isEmpty(), "Expected the transaction result to indicate a failure"); + } + + @Test + void testRunTransactionWithConflict() { + + Address miningBeneficiary = Address.fromHexString("0x1"); + Wei blobGasPrice = Wei.ZERO; + + Mockito.when( + transactionProcessor.processTransaction( + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any())) + .thenReturn( + TransactionProcessingResult.successful( + Collections.emptyList(), 0, 0, Bytes.EMPTY, ValidationResult.valid())); + + processor.runTransaction( + worldState, + blockHeader, + 0, + transaction, + miningBeneficiary, + (blockNumber) -> Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + verify(transactionProcessor, times(1)) + .processTransaction( + any(DiffBasedWorldStateUpdateAccumulator.class), + eq(blockHeader), + eq(transaction), + eq(miningBeneficiary), + any(OperationTracer.class), + any(BlockHashOperation.BlockHashLookup.class), + eq(true), + eq(TransactionValidationParams.processingBlock()), + eq(privateMetadataUpdater), + eq(blobGasPrice)); + + // simulate a conflict + when(transactionCollisionDetector.hasCollision(any(), any(), any(), any())).thenReturn(true); + + Optional result = + processor.applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()); + assertTrue(result.isEmpty(), "Expected no transaction result to be applied due to conflict"); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java new file mode 100644 index 00000000000..0cd1bad3c57 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java @@ -0,0 +1,290 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.mainnet.parallelization; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue; +import org.hyperledger.besu.evm.internal.EvmConfiguration; + +import java.math.BigInteger; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class TransactionCollisionDetectorTest { + + private TransactionCollisionDetector collisionDetector; + @Mock BonsaiWorldState worldState; + BonsaiWorldStateUpdateAccumulator bonsaiUpdater; + BonsaiWorldStateUpdateAccumulator trxUpdater; + + @BeforeEach + public void setUp() { + collisionDetector = new TransactionCollisionDetector(); + bonsaiUpdater = + new BonsaiWorldStateUpdateAccumulator( + worldState, (__, ___) -> {}, (__, ___) -> {}, EvmConfiguration.DEFAULT); + trxUpdater = + new BonsaiWorldStateUpdateAccumulator( + worldState, (__, ___) -> {}, (__, ___) -> {}, EvmConfiguration.DEFAULT); + } + + private Transaction createTransaction(final Address sender, final Address to) { + return new Transaction.Builder() + .nonce(1) + .gasPrice(Wei.of(1)) + .gasLimit(21000) + .to(to) + .value(Wei.ZERO) + .payload(Bytes.EMPTY) + .chainId(BigInteger.ONE) + .sender(sender) + .build(); + } + + private BonsaiAccount createAccount(final Address address) { + return new BonsaiAccount( + worldState, + address, + Hash.hash(Address.ZERO), + 0, + Wei.ONE, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY, + false); + } + + @Test + void testCollisionWithModifiedBalance() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setBalance(Wei.MAX_WEI); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedNonce() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setNonce(1); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedCode() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setCode(Bytes.repeat((byte) 0x01, 10)); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedStorageRoot() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setStorageRoot(Hash.EMPTY); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithMiningBeneficiaryAddress() { + final Address miningBeneficiary = Address.ZERO; + final Address address = Address.fromHexString("0x1"); + + final Transaction transaction = createTransaction(miningBeneficiary, address); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + miningBeneficiary, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected collision with the mining beneficiary address as sender"); + } + + @Test + void testCollisionWithAnotherMiningBeneficiaryAddress() { + final Address miningBeneficiary = Address.ZERO; + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount miningBeneficiaryValue = createAccount(address); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the mining beneficiary is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put( + miningBeneficiary, + new DiffBasedValue<>(miningBeneficiaryValue, miningBeneficiaryValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + miningBeneficiary, + new ParallelizedTransactionContext(trxUpdater, null, true, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected collision with the read mining beneficiary address"); + } + + @Test + void testCollisionWithDeletedAddress() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount accountValue = createAccount(address); + + // Simulate that the address was deleted in the block + bonsaiUpdater.getDeletedAccountAddresses().add(address); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the deleted address is read in the next transaction + trxUpdater.getAccountsToUpdate().put(address, new DiffBasedValue<>(accountValue, accountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the deleted address"); + } + + @Test + void testCollisionWithNoModifiedAddress() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + + // Simulate that the address was already read in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertFalse(hasCollision, "Expected no collision with the read address"); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java index 845b859ef73..388a112699a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java @@ -105,7 +105,9 @@ public abstract class AbstractIsolationTests { MainnetProtocolSchedule.fromConfig( GenesisConfigFile.fromResource("/dev.json").getConfigOptions(), MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); protected final GenesisState genesisState = GenesisState.fromConfig(GenesisConfigFile.fromResource("/dev.json"), protocolSchedule); protected final MutableBlockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java index ac3b8f2fc62..b11afeb4c56 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.nio.ByteBuffer; @@ -60,7 +61,9 @@ public void setup() { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } @Test diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java index 2b9105ed46d..72f089a53eb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.nio.ByteBuffer; @@ -67,7 +68,9 @@ public void blockHeadersRoundTrip() throws IOException { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())); + new BadBlockManager(), + false, + new NoOpMetricsSystem())); for (int i = 0; i < 50; ++i) { Assertions.assertThat(readHeaders.get(i)).isEqualTo(headers.get(i)); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java index 4bad73ebb64..5f7baaff418 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java @@ -59,7 +59,9 @@ public class ChainHeadTrackerTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private final TrailingPeerLimiter trailingPeerLimiter = mock(TrailingPeerLimiter.class); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index 9afba66ad3a..cfc9f9dc123 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -48,6 +48,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.referencetests.ForestReferenceTestWorldState; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -93,7 +94,11 @@ public class BackwardSyncContextTest { @Spy private ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); @Spy private ProtocolSpec protocolSpec = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java index ecb72881ed4..6dc69ea274e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.testutil.DeterministicEthScheduler; @@ -70,7 +71,11 @@ public class BackwardSyncStepTest { private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private final DeterministicEthScheduler ethScheduler = new DeterministicEthScheduler(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java index 5fb47a557ac..a5d2cf61045 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.referencetests.ForestReferenceTestWorldState; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.nio.charset.StandardCharsets; @@ -73,7 +74,11 @@ public class ForwardSyncStepTest { private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private MutableBlockchain localBlockchain; GenericKeyValueStorageFacade headersStorage; GenericKeyValueStorageFacade blocksStorage; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index 23eb9d02bf6..cd780c2dc99 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -201,7 +201,9 @@ protected static ExecutionContextTestFixture createExecutionContextTestFixtureBa false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 8e9bda89c05..c679183b0ff 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -123,7 +123,9 @@ public TestNode( false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, protocolSchedule); final BlockHeaderFunctions blockHeaderFunctions = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index ef8d0701782..5742637c3e8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -379,7 +379,9 @@ private void setupScheduleWith(final StubGenesisConfigOptions config) { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); protocolContext = mock(ProtocolContext.class); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index db70ccf41f0..4f10650273a 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.EvmSpecVersion; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Locale; @@ -80,7 +81,12 @@ ProtocolSchedule provideProtocolSchedule( } return MainnetProtocolSchedule.fromConfig( - configOptions, evmConfiguration, MiningParameters.newDefault(), new BadBlockManager()); + configOptions, + evmConfiguration, + MiningParameters.newDefault(), + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } public static Map> createSchedules() { @@ -145,7 +151,9 @@ private static Supplier createSchedule(final GenesisConfigOpti false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } } diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 11db6b8eeee..3c073136acd 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -194,6 +194,7 @@ dependencies { referenceTestImplementation project(path: ':config') referenceTestImplementation project(path: ':datatypes') referenceTestImplementation project(path: ':ethereum:core') + referenceTestImplementation project(path: ':metrics:core') referenceTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') referenceTestImplementation project(path: ':ethereum:rlp') referenceTestImplementation project(path: ':ethereum:rlp', configuration: 'testSupportArtifacts') diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 8ac419f7a68..5dfb12f1d61 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Arrays; @@ -130,7 +131,9 @@ private static ProtocolSchedule createSchedule(final GenesisConfigOptions option false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java index 6377b1ae3ba..00733de1f8e 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.checkerframework.checker.units.qual.N; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.config.StubGenesisConfigOptions; @@ -43,6 +44,7 @@ import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -59,64 +61,64 @@ public static Stream getTestParametersForConfig() throws IOException MainnetProtocolSchedule.fromConfig( GenesisConfigFile.mainnet() .getConfigOptions(postMergeOverrides), - EvmConfiguration.DEFAULT, MiningParameters.newDefault(), new BadBlockManager())), + EvmConfiguration.DEFAULT, MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem())), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfByzantium/difficultyByzantium.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfConstantinople/difficultyConstantinople.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random_to20M.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfFrontier/difficultyFrontier.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfHomestead/difficultyHomestead.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) )); } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index fd39ef7f44c..32d4e0bab10 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -161,7 +161,12 @@ private boolean buildContext( JsonUtil.getObjectNode(genesisConfig, "config").get()); protocolSchedule = MainnetProtocolSchedule.fromConfig( - jsonGenesisConfigOptions, EvmConfiguration.DEFAULT, miningParameters, badBlockManager); + jsonGenesisConfigOptions, + EvmConfiguration.DEFAULT, + miningParameters, + badBlockManager, + false, + new NoOpMetricsSystem()); if ("NoReward".equalsIgnoreCase(sealEngine)) { protocolSchedule = new NoRewardProtocolScheduleWrapper(protocolSchedule, badBlockManager); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java index 34e28bbb32f..f139386118a 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.datatypes.Address; 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; @@ -85,6 +86,17 @@ default void tracePrepareTransaction(final WorldView worldView, final Transactio */ default void traceStartTransaction(final WorldView worldView, final Transaction transaction) {} + /** + * Trace the end of a transaction just before mining reward. + * + * @param worldView an immutable view of the execution context + * @param tx the transaction that just concluded + * @param miningReward the reward that the mining beneficiary will receive. + */ + default void traceBeforeRewardTransaction( + final WorldView worldView, final Transaction tx, final Wei miningReward) {} + ; + /** * Trace the end of a transaction. * diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java index d419a6ac7c5..4151320177b 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java @@ -53,7 +53,9 @@ public enum BesuMetricCategory implements MetricCategory { /** Transaction pool besu metric category. */ TRANSACTION_POOL("transaction_pool"), /** Stratum besu metric category. */ - STRATUM("stratum"); + STRATUM("stratum"), + /** Block processing besu metric category. */ + BLOCK_PROCESSING("block_processing"); private static final Optional BESU_PREFIX = Optional.of("besu_");