From ebb883075fe832be6e55e1822731a6e5f8a6f930 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 22 May 2024 10:02:34 -0700 Subject: [PATCH] Feature/fleet mode rebase (#6641) * fleet mode squash commit rebase Signed-off-by: garyschulte --- .../dsl/node/ThreadBesuNodeRunner.java | 9 +- .../acceptance/dsl/privacy/PrivacyNode.java | 4 +- .../java/org/hyperledger/besu/Runner.java | 10 ++ .../org/hyperledger/besu/cli/BesuCommand.java | 48 ++++- .../options/stable/JsonRpcHttpOptions.java | 9 + .../options/unstable/ChainPruningOptions.java | 41 ++++- .../controller/BesuControllerBuilder.java | 20 +-- .../besu/services/BesuConfigurationImpl.java | 48 ++++- .../besu/services/BesuEventsImpl.java | 5 + .../besu/services/BesuPluginContextImpl.java | 19 ++ .../besu/services/BlockchainServiceImpl.java | 49 +++++- .../besu/services/P2PServiceImpl.java | 44 +++++ .../services/RlpConverterServiceImpl.java | 82 +++++++++ .../services/SynchronizationServiceImpl.java | 166 ++++++++++++++++++ .../services/TransactionPoolServiceImpl.java | 43 +++++ .../org/hyperledger/besu/PrivacyTest.java | 4 +- .../java/org/hyperledger/besu/RunnerTest.java | 4 +- .../besu/cli/CommandTestAbstract.java | 3 +- ...nsusScheduleBesuControllerBuilderTest.java | 3 +- .../services/RlpConverterServiceImplTest.java | 54 ++++++ .../MigratingMiningCoordinatorTest.java | 3 +- .../hyperledger/besu/datatypes/BlobGas.java | 4 +- .../chain/ChainPrunerConfiguration.java | 13 +- .../ethereum/chain/DefaultBlockchain.java | 3 +- .../ethereum/chain/MutableBlockchain.java | 2 + .../besu/ethereum/core/BlockHeader.java | 2 +- .../common/GenesisWorldStateProvider.java | 4 +- .../bonsai/BonsaiWorldStateProvider.java | 26 ++- .../BonsaiCachedWorldStorageManager.java | 11 +- .../NoOpBonsaiCachedWorldStorageManager.java | 3 +- ...nsaiSnapshotWorldStateKeyValueStorage.java | 9 + .../bonsai/worldview/BonsaiWorldState.java | 72 +++++--- .../common/DiffBasedWorldStateProvider.java | 17 ++ .../diffbased/common/StorageSubscriber.java | 2 + .../DiffBasedCachedWorldStorageManager.java | 22 ++- .../DiffBasedWorldStateKeyValueStorage.java | 5 + .../common/trielog/TrieLogManager.java | 40 ++++- .../common/worldview/DiffBasedWorldState.java | 52 ++++-- .../worldview/DiffBasedWorldStateConfig.java | 79 +++++++++ .../BlockImportExceptionHandlingTest.java | 4 +- .../ethereum/chain/ChainDataPrunerTest.java | 2 + .../bonsai/AbstractIsolationTests.java | 10 ++ .../diffbased/bonsai/LogRollingTests.java | 19 +- .../trie/diffbased/bonsai/RollingImport.java | 4 +- .../worldview/BonsaiWorldStateTest.java | 4 +- .../WorldStateDownloaderBenchmark.java | 4 +- .../eth/sync/AbstractSyncTargetManager.java | 14 ++ .../eth/sync/PipelineChainDownloader.java | 1 + .../evmtool/EvmToolCommandOptionsModule.java | 2 +- .../internal/PeerDiscoveryController.java | 1 + .../internal/RecursivePeerRefreshState.java | 20 +++ .../BonsaiReferenceTestWorldState.java | 7 +- .../besu/ethereum/trie/NoOpMerkleTrie.java | 123 +++++++++++++ plugin-api/build.gradle | 2 +- .../hyperledger/besu/plugin/BesuPlugin.java | 3 + .../plugin/services/BesuConfiguration.java | 15 ++ .../besu/plugin/services/BesuEvents.java | 8 + .../plugin/services/BlockchainService.java | 34 ++++ .../besu/plugin/services/TrieLogService.java | 3 +- .../besu/plugin/services/p2p/P2PService.java | 27 +++ .../services/rlp/RlpConverterService.java | 74 ++++++++ .../services/sync/SynchronizationService.java | 62 +++++++ .../sync/WorldStateConfiguration.java | 26 +++ .../TransactionPoolService.java | 26 +++ .../services/trielogs/TrieLogProvider.java | 27 +++ 65 files changed, 1425 insertions(+), 131 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/services/P2PServiceImpl.java create mode 100644 besu/src/main/java/org/hyperledger/besu/services/RlpConverterServiceImpl.java create mode 100644 besu/src/main/java/org/hyperledger/besu/services/SynchronizationServiceImpl.java create mode 100644 besu/src/main/java/org/hyperledger/besu/services/TransactionPoolServiceImpl.java create mode 100644 besu/src/test/java/org/hyperledger/besu/services/RlpConverterServiceImplTest.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldStateConfig.java create mode 100644 ethereum/trie/src/main/java/org/hyperledger/besu/ethereum/trie/NoOpMerkleTrie.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/p2p/P2PService.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/rlp/RlpConverterService.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/SynchronizationService.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/WorldStateConfiguration.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/transactionpool/TransactionPoolService.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index 073e0bd1d1b..0448d324e64 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -180,11 +180,10 @@ public void startNode(final BesuNode node) { .from(node.getMiningParameters()) .transactionSelectionService(transactionSelectionServiceImpl) .build(); - commonPluginConfiguration.init( - dataDir, - dataDir.resolve(DATABASE_PATH), - node.getDataStorageConfiguration(), - miningParameters); + commonPluginConfiguration + .init(dataDir, dataDir.resolve(DATABASE_PATH), node.getDataStorageConfiguration()) + .withMiningParameters(miningParameters); + final BesuPluginContextImpl besuPluginContext = besuPluginContextMap.computeIfAbsent( node, diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java index c9487ebcd67..32a5a0fbf4a 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java @@ -274,7 +274,9 @@ public NodeConfiguration getConfiguration() { private PrivacyStorageProvider createKeyValueStorageProvider( final Path dataLocation, final Path dbLocation) { final var besuConfiguration = new BesuConfigurationImpl(); - besuConfiguration.init(dataLocation, dbLocation, null, besuConfig.getMiningParameters()); + besuConfiguration + .init(dataLocation, dbLocation, null) + .withMiningParameters(besuConfig.getMiningParameters()); return new PrivacyKeyValueStorageProviderBuilder() .withStorageFactory( new RocksDBKeyValuePrivacyStorageFactory( diff --git a/besu/src/main/java/org/hyperledger/besu/Runner.java b/besu/src/main/java/org/hyperledger/besu/Runner.java index 32c4a46ddeb..4444f7acf72 100644 --- a/besu/src/main/java/org/hyperledger/besu/Runner.java +++ b/besu/src/main/java/org/hyperledger/besu/Runner.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolEvictionService; import org.hyperledger.besu.ethereum.p2p.network.NetworkRunner; +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; import org.hyperledger.besu.ethereum.stratum.StratumServer; import org.hyperledger.besu.ethstats.EthStatsService; import org.hyperledger.besu.metrics.MetricsService; @@ -422,6 +423,15 @@ Optional getLocalEnode() { return networkRunner.getNetwork().getLocalEnode(); } + /** + * get P2PNetwork service. + * + * @return p2p network service. + */ + public P2PNetwork getP2PNetwork() { + return networkRunner.getNetwork(); + } + @FunctionalInterface private interface SynchronousShutdown { /** 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 ccbc619b5ac..bd47630fad6 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -172,21 +172,29 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; +import org.hyperledger.besu.plugin.services.p2p.P2PService; +import org.hyperledger.besu.plugin.services.rlp.RlpConverterService; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModule; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.PrivacyKeyValueStorageFactory; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBPlugin; +import org.hyperledger.besu.plugin.services.sync.SynchronizationService; +import org.hyperledger.besu.plugin.services.transactionpool.TransactionPoolService; import org.hyperledger.besu.services.BesuConfigurationImpl; import org.hyperledger.besu.services.BesuEventsImpl; import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BlockchainServiceImpl; +import org.hyperledger.besu.services.P2PServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PicoCLIOptionsImpl; import org.hyperledger.besu.services.PrivacyPluginServiceImpl; +import org.hyperledger.besu.services.RlpConverterServiceImpl; import org.hyperledger.besu.services.RpcEndpointServiceImpl; import org.hyperledger.besu.services.SecurityModuleServiceImpl; import org.hyperledger.besu.services.StorageServiceImpl; +import org.hyperledger.besu.services.SynchronizationServiceImpl; import org.hyperledger.besu.services.TraceServiceImpl; +import org.hyperledger.besu.services.TransactionPoolServiceImpl; import org.hyperledger.besu.services.TransactionPoolValidatorServiceImpl; import org.hyperledger.besu.services.TransactionSelectionServiceImpl; import org.hyperledger.besu.services.TransactionSimulationServiceImpl; @@ -1161,12 +1169,15 @@ public void run() { final var runner = buildRunner(); runner.startExternalServices(); - startPlugins(); + startPlugins(runner); validatePluginOptions(); setReleaseMetrics(); preSynchronization(); runner.startEthereumMainLoop(); + + besuPluginContext.afterExternalServicesMainLoop(); + runner.awaitStop(); } catch (final Exception e) { @@ -1327,7 +1338,7 @@ private Runner buildRunner() { pidPath); } - private void startPlugins() { + private void startPlugins(final Runner runner) { blockchainServiceImpl.init( besuController.getProtocolContext(), besuController.getProtocolSchedule()); transactionSimulationServiceImpl.init( @@ -1348,6 +1359,26 @@ private void startPlugins() { besuController.getProtocolContext().getBadBlockManager())); besuPluginContext.addService(MetricsSystem.class, getMetricsSystem()); + besuPluginContext.addService(BlockchainService.class, blockchainServiceImpl); + + besuPluginContext.addService( + SynchronizationService.class, + new SynchronizationServiceImpl( + besuController.getProtocolContext(), + besuController.getProtocolSchedule(), + besuController.getSyncState(), + besuController.getProtocolContext().getWorldStateArchive())); + + besuPluginContext.addService(P2PService.class, new P2PServiceImpl(runner.getP2PNetwork())); + + besuPluginContext.addService( + TransactionPoolService.class, + new TransactionPoolServiceImpl(besuController.getTransactionPool())); + + besuPluginContext.addService( + RlpConverterService.class, + new RlpConverterServiceImpl(besuController.getProtocolSchedule())); + besuPluginContext.addService( TraceService.class, new TraceServiceImpl( @@ -1653,11 +1684,11 @@ private void validateRpcWsOptions() { private void validateChainDataPruningParams() { if (unstableChainPruningOptions.getChainDataPruningEnabled() && unstableChainPruningOptions.getChainDataPruningBlocksRetained() - < ChainPruningOptions.DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED) { + < unstableChainPruningOptions.getChainDataPruningBlocksRetainedLimit()) { throw new ParameterException( this.commandLine, "--Xchain-pruning-blocks-retained must be >= " - + ChainPruningOptions.DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED); + + unstableChainPruningOptions.getChainDataPruningBlocksRetainedLimit()); } } @@ -1843,11 +1874,10 @@ public BesuController buildController() { * @return instance of BesuControllerBuilder */ public BesuControllerBuilder getControllerBuilder() { - pluginCommonConfiguration.init( - dataDir(), - dataDir().resolve(DATABASE_PATH), - getDataStorageConfiguration(), - miningParametersSupplier.get()); + pluginCommonConfiguration + .init(dataDir(), dataDir().resolve(DATABASE_PATH), getDataStorageConfiguration()) + .withMiningParameters(getMiningParameters()) + .withJsonRpcHttpOptions(jsonRpcHttpOptions); final KeyValueStorageProvider storageProvider = keyValueStorageProvider(keyValueStorageName); return controllerBuilderFactory .fromEthNetworkConfig(updateNetworkConfig(network), getDefaultSyncModeIfNotSet()) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java index a47c5e9ce2d..026b83b5537 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/JsonRpcHttpOptions.java @@ -475,6 +475,15 @@ public List getRpcHttpApis() { return rpcHttpApis; } + /** + * Returns the host for RPC over HTTP. + * + * @return The port number + */ + public String getRpcHttpHost() { + return rpcHttpHost; + } + /** * Returns the port for RPC over HTTP. * diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/ChainPruningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/ChainPruningOptions.java index 8eaed2d084c..0a59ef9b04e 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/ChainPruningOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/ChainPruningOptions.java @@ -28,10 +28,17 @@ public class ChainPruningOptions implements CLIOptions private static final String CHAIN_PRUNING_ENABLED_FLAG = "--Xchain-pruning-enabled"; private static final String CHAIN_PRUNING_BLOCKS_RETAINED_FLAG = "--Xchain-pruning-blocks-retained"; + private static final String CHAIN_PRUNING_BLOCKS_RETAINED_LIMIT_FLAG = + "--Xchain-pruning-blocks-retained-limit"; private static final String CHAIN_PRUNING_FREQUENCY_FLAG = "--Xchain-pruning-frequency"; - /** The constant DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED. */ - public static final long DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED = 7200; + /** + * The "CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED_LIMIT" field sets the minimum limit for the + * "CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED" value. For most networks, the default value of this + * limit is the safest. Reducing this value requires careful consideration and understanding of + * the potential implications. Lowering this limit may have unintended side effects. + */ + public static final long CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED_LIMIT = 7200; /** The constant DEFAULT_CHAIN_DATA_PRUNING_FREQUENCY. */ public static final int DEFAULT_CHAIN_DATA_PRUNING_FREQUENCY = 256; @@ -47,11 +54,21 @@ public class ChainPruningOptions implements CLIOptions hidden = true, names = {CHAIN_PRUNING_BLOCKS_RETAINED_FLAG}, description = - "The number of recent blocks for which to keep the chain data. Must be >= " - + DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED + "The number of recent blocks for which to keep the chain data. Should be >= " + + CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED_LIMIT + + " (default: ${DEFAULT-VALUE})") + private final Long chainDataPruningBlocksRetained = CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED_LIMIT; + + @CommandLine.Option( + hidden = true, + names = {CHAIN_PRUNING_BLOCKS_RETAINED_LIMIT_FLAG}, + description = + "Allows setting the limit below which no more blocks can be pruned. This prevents setting a value lower than this for " + + CHAIN_PRUNING_BLOCKS_RETAINED_FLAG + + ". This flag should be used with caution as reducing the limit may have unintended side effects." + " (default: ${DEFAULT-VALUE})") - private final Long chainDataPruningBlocksRetained = - DEFAULT_CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED; + private final Long chainDataPruningBlocksRetainedLimit = + CHAIN_DATA_PRUNING_MIN_BLOCKS_RETAINED_LIMIT; @CommandLine.Option( hidden = true, @@ -91,11 +108,21 @@ public Long getChainDataPruningBlocksRetained() { return chainDataPruningBlocksRetained; } + /** + * Get the configured number of retained blocks for chain pruning. + * + * @return the number of retained blocks + */ + public Long getChainDataPruningBlocksRetainedLimit() { + return chainDataPruningBlocksRetainedLimit; + } + @Override public ChainPrunerConfiguration toDomainObject() { return new ChainPrunerConfiguration( chainDataPruningEnabled, chainDataPruningBlocksRetained, + chainDataPruningBlocksRetainedLimit, chainDataPruningBlocksFrequency.getValue()); } @@ -106,6 +133,8 @@ public List getCLIOptions() { chainDataPruningEnabled.toString(), CHAIN_PRUNING_BLOCKS_RETAINED_FLAG, chainDataPruningBlocksRetained.toString(), + CHAIN_PRUNING_BLOCKS_RETAINED_LIMIT_FLAG, + chainDataPruningBlocksRetainedLimit.toString(), CHAIN_PRUNING_FREQUENCY_FLAG, chainDataPruningBlocksFrequency.toString()); } 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 d801528cf55..322f596e160 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -610,16 +610,6 @@ public BesuController build() { blockchain, worldStateArchive, protocolSchedule, this::createConsensusContext); validateContext(protocolContext); - if (chainPrunerConfiguration.getChainPruningEnabled()) { - final ChainDataPruner chainDataPruner = createChainPruner(blockchainStorage); - blockchain.observeBlockAdded(chainDataPruner); - LOG.info( - "Chain data pruning enabled with recent blocks retained to be: " - + chainPrunerConfiguration.getChainPruningBlocksRetained() - + " and frequency to be: " - + chainPrunerConfiguration.getChainPruningBlocksFrequency()); - } - protocolSchedule.setPublicWorldStateArchiveForPrivacyBlockProcessor( protocolContext.getWorldStateArchive()); @@ -668,6 +658,16 @@ public BesuController build() { final boolean fullSyncDisabled = !SyncMode.isFullSync(syncConfig.getSyncMode()); final SyncState syncState = new SyncState(blockchain, ethPeers, fullSyncDisabled, checkpoint); + if (chainPrunerConfiguration.getChainPruningEnabled()) { + final ChainDataPruner chainDataPruner = createChainPruner(blockchainStorage); + blockchain.observeBlockAdded(chainDataPruner); + LOG.info( + "Chain data pruning enabled with recent blocks retained to be: " + + chainPrunerConfiguration.getChainPruningBlocksRetained() + + " and frequency to be: " + + chainPrunerConfiguration.getChainPruningBlocksFrequency()); + } + final TransactionPool transactionPool = TransactionPoolFactory.createTransactionPool( protocolSchedule, diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java index 875929da3c2..0adbda23b74 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.services; +import org.hyperledger.besu.cli.options.stable.JsonRpcHttpOptions; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; @@ -21,13 +22,18 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.nio.file.Path; +import java.util.Optional; /** A concrete implementation of BesuConfiguration which is used in Besu plugin framework. */ public class BesuConfigurationImpl implements BesuConfiguration { private Path storagePath; private Path dataPath; private DataStorageConfiguration dataStorageConfiguration; - private MiningParameters miningParameters; + + // defaults + private MiningParameters miningParameters = MiningParameters.newDefault(); + private Optional rpcHttpHost = Optional.of("http://localhost"); + private Optional rpcHttpPort = Optional.of(8545); /** Default Constructor. */ public BesuConfigurationImpl() {} @@ -38,17 +44,49 @@ public BesuConfigurationImpl() {} * @param dataPath The Path representing data folder * @param storagePath The path representing storage folder * @param dataStorageConfiguration The data storage configuration - * @param miningParameters The mining parameters + * @return BesuConfigurationImpl instance */ - public void init( + public BesuConfigurationImpl init( final Path dataPath, final Path storagePath, - final DataStorageConfiguration dataStorageConfiguration, - final MiningParameters miningParameters) { + final DataStorageConfiguration dataStorageConfiguration) { this.dataPath = dataPath; this.storagePath = storagePath; this.dataStorageConfiguration = dataStorageConfiguration; + return this; + } + + /** + * Set the mining parameters + * + * @param miningParameters configured mining parameters + * @return BesuConfigurationImpl instance + */ + public BesuConfigurationImpl withMiningParameters(final MiningParameters miningParameters) { this.miningParameters = miningParameters; + return this; + } + + /** + * Set the RPC http options + * + * @param rpcHttpOptions configured rpc http options + * @return BesuConfigurationImpl instance + */ + public BesuConfigurationImpl withJsonRpcHttpOptions(final JsonRpcHttpOptions rpcHttpOptions) { + this.rpcHttpHost = Optional.ofNullable(rpcHttpOptions.getRpcHttpHost()); + this.rpcHttpPort = Optional.ofNullable(rpcHttpOptions.getRpcHttpPort()); + return this; + } + + @Override + public Optional getRpcHttpHost() { + return rpcHttpHost; + } + + @Override + public Optional getRpcHttpPort() { + return rpcHttpPort; } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java index 5e6a63df407..aeb7025872a 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java @@ -114,6 +114,11 @@ public void removeBlockReorgListener(final long listenerIdentifier) { blockchain.removeObserver(listenerIdentifier); } + @Override + public long addInitialSyncCompletionListener(final InitialSyncCompletionListener listener) { + return syncState.subscribeCompletionReached(listener); + } + @Override public long addTransactionAddedListener(final TransactionAddedListener listener) { return transactionPool.subscribePendingTransactions(listener::onTransactionAdded); diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java index e7108a02d1a..6aa64ac5106 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java @@ -262,6 +262,25 @@ public void startPlugins() { state = Lifecycle.BEFORE_MAIN_LOOP_FINISHED; } + /** Execute all plugin setup code after external services. */ + public void afterExternalServicesMainLoop() { + checkState( + state == Lifecycle.BEFORE_MAIN_LOOP_FINISHED, + "BesuContext should be in state %s but it was in %s", + Lifecycle.BEFORE_MAIN_LOOP_FINISHED, + state); + final Iterator pluginsIterator = registeredPlugins.iterator(); + + while (pluginsIterator.hasNext()) { + final BesuPlugin plugin = pluginsIterator.next(); + try { + plugin.afterExternalServicePostMainLoop(); + } finally { + pluginsIterator.remove(); + } + } + } + /** Stop plugins. */ public void stopPlugins() { checkState( diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java index c6d37ad6ae9..5005e5f7ccd 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java @@ -17,17 +17,22 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.TransactionReceipt; import org.hyperledger.besu.plugin.services.BlockchainService; +import java.util.List; import java.util.Optional; import java.util.function.Supplier; +import java.util.stream.Collectors; /** The Blockchain service implementation. */ @Unstable @@ -35,9 +40,7 @@ public class BlockchainServiceImpl implements BlockchainService { private ProtocolContext protocolContext; private ProtocolSchedule protocolSchedule; - - /** Create a new instance */ - public BlockchainServiceImpl() {} + private MutableBlockchain blockchain; /** * Instantiates a new Blockchain service. @@ -48,6 +51,7 @@ public BlockchainServiceImpl() {} public void init(final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule) { this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; + this.blockchain = protocolContext.getBlockchain(); } /** @@ -91,6 +95,43 @@ public Optional getNextBlockBaseFee() { feeMarket.targetGasUsed(chainHeadHeader))); } + @Override + public Optional> getReceiptsByBlockHash(final Hash blockHash) { + return blockchain + .getTxReceipts(blockHash) + .map( + list -> list.stream().map(TransactionReceipt.class::cast).collect(Collectors.toList())); + } + + @Override + public void storeBlock( + final BlockHeader blockHeader, + final BlockBody blockBody, + final List receipts) { + final org.hyperledger.besu.ethereum.core.BlockHeader coreHeader = + (org.hyperledger.besu.ethereum.core.BlockHeader) blockHeader; + final org.hyperledger.besu.ethereum.core.BlockBody coreBody = + (org.hyperledger.besu.ethereum.core.BlockBody) blockBody; + final List coreReceipts = + receipts.stream() + .map(org.hyperledger.besu.ethereum.core.TransactionReceipt.class::cast) + .toList(); + blockchain.unsafeImportBlock( + new Block(coreHeader, coreBody), + coreReceipts, + Optional.ofNullable(blockchain.calculateTotalDifficulty(coreHeader))); + } + + @Override + public Optional getSafeBlock() { + return blockchain.getSafeBlock(); + } + + @Override + public Optional getFinalizedBlock() { + return blockchain.getFinalized(); + } + private static BlockContext blockContext( final Supplier blockHeaderSupplier, final Supplier blockBodySupplier) { diff --git a/besu/src/main/java/org/hyperledger/besu/services/P2PServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/P2PServiceImpl.java new file mode 100644 index 00000000000..dc1fb0833a8 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/P2PServiceImpl.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.services; + +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; +import org.hyperledger.besu.plugin.services.p2p.P2PService; + +/** Service to enable and disable P2P discovery. */ +public class P2PServiceImpl implements P2PService { + + private final P2PNetwork p2PNetwork; + + /** + * Creates a new P2PServiceImpl. + * + * @param p2PNetwork the P2P network to enable and disable. + */ + public P2PServiceImpl(final P2PNetwork p2PNetwork) { + this.p2PNetwork = p2PNetwork; + } + + /** Enables P2P discovery. */ + @Override + public void enableDiscovery() { + p2PNetwork.start(); + } + + @Override + public void disableDiscovery() { + p2PNetwork.stop(); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/services/RlpConverterServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/RlpConverterServiceImpl.java new file mode 100644 index 00000000000..53b3541a5b0 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/RlpConverterServiceImpl.java @@ -0,0 +1,82 @@ +/* + * 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.services; + +import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.TransactionReceipt; +import org.hyperledger.besu.plugin.services.rlp.RlpConverterService; + +import org.apache.tuweni.bytes.Bytes; + +/** RLP Serialiaztion/Deserialization service. */ +public class RlpConverterServiceImpl implements RlpConverterService { + + private final BlockHeaderFunctions blockHeaderFunctions; + + /** + * Constructor for RlpConverterServiceImpl. + * + * @param protocolSchedule the protocol schedule. + */ + public RlpConverterServiceImpl(final ProtocolSchedule protocolSchedule) { + this.blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); + } + + @Override + public BlockHeader buildHeaderFromRlp(final Bytes rlp) { + return org.hyperledger.besu.ethereum.core.BlockHeader.readFrom( + RLP.input(rlp), blockHeaderFunctions); + } + + @Override + public BlockBody buildBodyFromRlp(final Bytes rlp) { + return org.hyperledger.besu.ethereum.core.BlockBody.readWrappedBodyFrom( + RLP.input(rlp), blockHeaderFunctions); + } + + @Override + public TransactionReceipt buildReceiptFromRlp(final Bytes rlp) { + return org.hyperledger.besu.ethereum.core.TransactionReceipt.readFrom(RLP.input(rlp)); + } + + @Override + public Bytes buildRlpFromHeader(final BlockHeader blockHeader) { + return RLP.encode( + org.hyperledger.besu.ethereum.core.BlockHeader.convertPluginBlockHeader( + blockHeader, blockHeaderFunctions) + ::writeTo); + } + + @Override + public Bytes buildRlpFromBody(final BlockBody blockBody) { + return RLP.encode( + rlpOutput -> + ((org.hyperledger.besu.ethereum.core.BlockBody) blockBody) + .writeWrappedBodyTo(rlpOutput)); + } + + @Override + public Bytes buildRlpFromReceipt(final TransactionReceipt receipt) { + return RLP.encode( + rlpOutput -> + ((org.hyperledger.besu.ethereum.core.TransactionReceipt) receipt) + .writeToForNetwork(rlpOutput)); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/services/SynchronizationServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/SynchronizationServiceImpl.java new file mode 100644 index 00000000000..898ede5d0d4 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/SynchronizationServiceImpl.java @@ -0,0 +1,166 @@ +/* + * 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.services; + +import org.hyperledger.besu.consensus.merge.MergeContext; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; +import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider; +import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.services.sync.SynchronizationService; + +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Synchronization service. */ +public class SynchronizationServiceImpl implements SynchronizationService { + + private static final Logger LOG = LoggerFactory.getLogger(SynchronizationServiceImpl.class); + + private final ProtocolContext protocolContext; + private final ProtocolSchedule protocolSchedule; + + private final SyncState syncState; + private final Optional worldStateArchive; + + /** + * Constructor for SynchronizationServiceImpl. + * + * @param protocolContext protocol context + * @param protocolSchedule protocol schedule + * @param syncState sync state + * @param worldStateArchive world state archive + */ + public SynchronizationServiceImpl( + final ProtocolContext protocolContext, + final ProtocolSchedule protocolSchedule, + final SyncState syncState, + final WorldStateArchive worldStateArchive) { + this.protocolContext = protocolContext; + this.protocolSchedule = protocolSchedule; + this.syncState = syncState; + this.worldStateArchive = + Optional.ofNullable(worldStateArchive) + .filter(z -> z instanceof DiffBasedWorldStateProvider) + .map(DiffBasedWorldStateProvider.class::cast); + } + + @Override + public void fireNewUnverifiedForkchoiceEvent( + final Hash head, final Hash safeBlock, final Hash finalizedBlock) { + final MergeContext mergeContext = protocolContext.getConsensusContext(MergeContext.class); + if (mergeContext != null) { + mergeContext.fireNewUnverifiedForkchoiceEvent(head, safeBlock, finalizedBlock); + protocolContext.getBlockchain().setFinalized(finalizedBlock); + protocolContext.getBlockchain().setSafeBlock(safeBlock); + } else { + LOG.atWarn() + .setMessage( + "The merge context is unavailable, hence the fork choice event cannot be triggered") + .log(); + } + } + + @Override + public boolean setHead(final BlockHeader blockHeader, final BlockBody blockBody) { + final BlockImporter blockImporter = + protocolSchedule + .getByBlockHeader((org.hyperledger.besu.ethereum.core.BlockHeader) blockHeader) + .getBlockImporter(); + return blockImporter + .importBlock( + protocolContext, + new Block( + (org.hyperledger.besu.ethereum.core.BlockHeader) blockHeader, + (org.hyperledger.besu.ethereum.core.BlockBody) blockBody), + HeaderValidationMode.SKIP_DETACHED) + .isImported(); + } + + @Override + public boolean setHeadUnsafe(final BlockHeader blockHeader, final BlockBody blockBody) { + final org.hyperledger.besu.ethereum.core.BlockHeader coreHeader = + (org.hyperledger.besu.ethereum.core.BlockHeader) blockHeader; + + final MutableBlockchain blockchain = protocolContext.getBlockchain(); + + if (worldStateArchive.flatMap(archive -> archive.getMutable(coreHeader, true)).isPresent()) { + if (coreHeader.getParentHash().equals(blockchain.getChainHeadHash())) { + LOG.atDebug() + .setMessage( + "Forwarding chain head to the block {} saved from a previous newPayload invocation") + .addArgument(coreHeader::toLogString) + .log(); + return blockchain.forwardToBlock(coreHeader); + } else { + LOG.atDebug() + .setMessage("New head {} is a chain reorg, rewind chain head to it") + .addArgument(coreHeader::toLogString) + .log(); + return blockchain.rewindToBlock(coreHeader.getBlockHash()); + } + } else { + LOG.atWarn() + .setMessage("The world state is unavailable, setting of head cannot be performed.") + .log(); + } + return false; + } + + @Override + public boolean isInitialSyncPhaseDone() { + return syncState.isInitialSyncPhaseDone(); + } + + @Override + public void disableWorldStateTrie() { + // TODO maybe find a best way in the future to delete and disable trie + worldStateArchive.ifPresent( + archive -> { + archive.getDefaultWorldStateConfig().setTrieDisabled(true); + final DiffBasedWorldStateKeyValueStorage worldStateStorage = + archive.getWorldStateKeyValueStorage(); + final Optional worldStateBlockHash = worldStateStorage.getWorldStateBlockHash(); + final Optional worldStateRootHash = worldStateStorage.getWorldStateRootHash(); + if (worldStateRootHash.isPresent() && worldStateBlockHash.isPresent()) { + worldStateStorage.clearTrie(); + // keep root and block hash in the trie branch + final DiffBasedWorldStateKeyValueStorage.Updater updater = worldStateStorage.updater(); + updater.saveWorldState( + worldStateBlockHash.get(), Bytes32.wrap(worldStateRootHash.get()), Bytes.EMPTY); + updater.commit(); + + // currently only bonsai needs an explicit upgrade to full flat db + if (worldStateStorage instanceof BonsaiWorldStateKeyValueStorage bonsaiStorage) { + bonsaiStorage.upgradeToFullFlatDbMode(); + } + } + }); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/services/TransactionPoolServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TransactionPoolServiceImpl.java new file mode 100644 index 00000000000..16d033ac9e4 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/TransactionPoolServiceImpl.java @@ -0,0 +1,43 @@ +/* + * 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.services; + +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.plugin.services.transactionpool.TransactionPoolService; + +/** Service to enable and disable the transaction pool. */ +public class TransactionPoolServiceImpl implements TransactionPoolService { + + private final TransactionPool transactionPool; + + /** + * Creates a new TransactionPoolServiceImpl. + * + * @param transactionPool the transaction pool to control + */ + public TransactionPoolServiceImpl(final TransactionPool transactionPool) { + this.transactionPool = transactionPool; + } + + @Override + public void disableTransactionPool() { + transactionPool.setDisabled(); + } + + @Override + public void enableTransactionPool() { + transactionPool.setEnabled(); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java index 7a4f05ad7fa..dc5b7003c84 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java @@ -137,7 +137,9 @@ private PrivacyStorageProvider createKeyValueStorageProvider( final DataStorageConfiguration dataStorageConfiguration, final MiningParameters miningParameters) { final var besuConfiguration = new BesuConfigurationImpl(); - besuConfiguration.init(dataDir, dbDir, dataStorageConfiguration, miningParameters); + besuConfiguration + .init(dataDir, dbDir, dataStorageConfiguration) + .withMiningParameters(miningParameters); return new PrivacyKeyValueStorageProviderBuilder() .withStorageFactory( new RocksDBKeyValuePrivacyStorageFactory( diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index f0125174d27..f6c6aac5f2f 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -391,7 +391,9 @@ private StorageProvider createKeyValueStorageProvider( final DataStorageConfiguration dataStorageConfiguration, final MiningParameters miningParameters) { final var besuConfiguration = new BesuConfigurationImpl(); - besuConfiguration.init(dataDir, dbDir, dataStorageConfiguration, miningParameters); + besuConfiguration + .init(dataDir, dbDir, dataStorageConfiguration) + .withMiningParameters(miningParameters); return new KeyValueStorageProviderBuilder() .withStorageFactory( new RocksDBKeyValueStorageFactory( 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 5216db7036b..1dfb5f449b7 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -127,6 +127,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -214,7 +215,7 @@ public abstract class CommandTestAbstract { @Mock protected TransactionSelectionServiceImpl txSelectionService; @Mock protected SecurityModuleServiceImpl securityModuleService; @Mock protected SecurityModule securityModule; - @Mock protected BesuConfigurationImpl commonPluginConfiguration; + @Spy protected BesuConfigurationImpl commonPluginConfiguration = new BesuConfigurationImpl(); @Mock protected KeyValueStorageFactory rocksDBStorageFactory; @Mock protected PrivacyKeyValueStorageFactory rocksDBSPrivacyStorageFactory; @Mock protected PicoCLIOptions cliOptions; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java index 12f36c9f6ec..5efeed50b24 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java @@ -30,7 +30,6 @@ import org.hyperledger.besu.ethereum.ConsensusContext; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.hyperledger.besu.ethereum.blockcreation.NoopMiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.MiningParameters; @@ -68,7 +67,7 @@ public class ConsensusScheduleBesuControllerBuilderTest { private @Mock ProtocolSchedule protocolSchedule1; private @Mock ProtocolSchedule protocolSchedule2; private @Mock ProtocolSchedule protocolSchedule3; - private @Mock NoopMiningCoordinator miningCoordinator1; + private @Mock MiningCoordinator miningCoordinator1; private @Mock BftMiningCoordinator miningCoordinator2; @Test diff --git a/besu/src/test/java/org/hyperledger/besu/services/RlpConverterServiceImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/RlpConverterServiceImplTest.java new file mode 100644 index 00000000000..7a3bdbbfe6b --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/services/RlpConverterServiceImplTest.java @@ -0,0 +1,54 @@ +/* + * 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.services; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; +import org.hyperledger.besu.plugin.data.BlockHeader; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +public class RlpConverterServiceImplTest { + + @Test + public void testBuildRlpFromHeader() { + // Arrange + RlpConverterServiceImpl rlpConverterServiceImpl = + new RlpConverterServiceImpl(ProtocolScheduleFixture.MAINNET); + // header with cancun fields + BlockHeader header = + new BlockHeaderTestFixture() + .timestamp(1710338135 + 1) + .baseFeePerGas(Wei.of(1000)) + .requestsRoot(Hash.ZERO) + .withdrawalsRoot(Hash.ZERO) + .blobGasUsed(500L) + .excessBlobGas(BlobGas.of(500L)) + .buildHeader(); + + Bytes rlpBytes = rlpConverterServiceImpl.buildRlpFromHeader(header); + BlockHeader deserialized = rlpConverterServiceImpl.buildHeaderFromRlp(rlpBytes); + // Assert + assertThat(header).isEqualTo(deserialized); + assertThat(header.getBlobGasUsed()).isEqualTo(deserialized.getBlobGasUsed()); + assertThat(header.getExcessBlobGas()).isEqualTo(deserialized.getExcessBlobGas()); + } +} diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinatorTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinatorTest.java index 640691f0d3e..f3edea81e6c 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinatorTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinatorTest.java @@ -30,7 +30,6 @@ import org.hyperledger.besu.consensus.common.bft.blockcreation.BftMiningCoordinator; import org.hyperledger.besu.consensus.common.bft.statemachine.BftEventHandler; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.hyperledger.besu.ethereum.blockcreation.NoopMiningCoordinator; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -122,7 +121,7 @@ public void stopShouldUnregisterThisCoordinatorAsObserver() { @Test public void onBlockAddedShouldNotDelegateWhenDelegateIsNoop() { - NoopMiningCoordinator mockNoopCoordinator = mock(NoopMiningCoordinator.class); + MiningCoordinator mockNoopCoordinator = mock(MiningCoordinator.class); coordinatorSchedule = createCoordinatorSchedule(mockNoopCoordinator, coordinator2); when(blockHeader.getNumber()).thenReturn(GENESIS_BLOCK_NUMBER); diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java index a64e79b19dd..9ac72b6d8ac 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlobGas.java @@ -16,6 +16,7 @@ import java.math.BigInteger; +import com.fasterxml.jackson.annotation.JsonValue; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.BaseUInt64Value; import org.apache.tuweni.units.bigints.UInt64; @@ -123,6 +124,7 @@ public BigInteger getAsBigInteger() { return toBigInteger(); } + @JsonValue @Override public String toHexString() { return super.toHexString(); @@ -140,6 +142,6 @@ public String toShortHexString() { * @return the blob gas */ public static BlobGas fromQuantity(final Quantity quantity) { - return BlobGas.wrap((Bytes) quantity); + return BlobGas.of(quantity.getAsBigInteger()); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainPrunerConfiguration.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainPrunerConfiguration.java index 19e2e37b363..67ad7f0a277 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainPrunerConfiguration.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainPrunerConfiguration.java @@ -16,15 +16,20 @@ public class ChainPrunerConfiguration { public static final ChainPrunerConfiguration DEFAULT = - new ChainPrunerConfiguration(false, 7200, 256); + new ChainPrunerConfiguration(false, 7200, 7200, 256); private final boolean enabled; private final long blocksRetained; private final long blocksFrequency; + private final long blocksRetainedLimit; public ChainPrunerConfiguration( - final boolean enabled, final long blocksRetained, final long blocksFrequency) { + final boolean enabled, + final long blocksRetained, + final long blocksRetainedLimit, + final long blocksFrequency) { this.enabled = enabled; this.blocksRetained = blocksRetained; + this.blocksRetainedLimit = blocksRetainedLimit; this.blocksFrequency = blocksFrequency; } @@ -32,6 +37,10 @@ public long getChainPruningBlocksRetained() { return blocksRetained; } + public long getBlocksRetainedLimit() { + return blocksRetainedLimit; + } + public boolean getChainPruningEnabled() { return enabled; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 0515deeb005..032ccb9f21f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -469,7 +469,8 @@ public synchronized void unsafeSetChainHead( updater.commit(); } - private Difficulty calculateTotalDifficulty(final BlockHeader blockHeader) { + @Override + public Difficulty calculateTotalDifficulty(final BlockHeader blockHeader) { if (blockHeader.getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER) { return blockHeader.getDifficulty(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/MutableBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/MutableBlockchain.java index da42e25afc3..5213974be31 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/MutableBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/MutableBlockchain.java @@ -56,6 +56,8 @@ void unsafeImportBlock( void unsafeSetChainHead(final BlockHeader blockHeader, final Difficulty totalDifficulty); + Difficulty calculateTotalDifficulty(final BlockHeader blockHeader); + /** * Rolls back the canonical chainhead to the specified block number. * diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java index f12024e11a1..46d2f0847a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java @@ -309,7 +309,7 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), pluginBlockHeader.getBlobGasUsed().map(Long::longValue).orElse(null), - pluginBlockHeader.getExcessBlobGas().map(BlobGas::fromQuantity).orElse(null), + pluginBlockHeader.getExcessBlobGas().map(BlobGas.class::cast).orElse(null), pluginBlockHeader.getParentBeaconBlockRoot().orElse(null), pluginBlockHeader .getRequestsRoot() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/common/GenesisWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/common/GenesisWorldStateProvider.java index 79855c1e52c..78bcb417e37 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/common/GenesisWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/common/GenesisWorldStateProvider.java @@ -22,6 +22,7 @@ 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.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; @@ -72,7 +73,8 @@ private static MutableWorldState createGenesisBonsaiWorldState() { bonsaiCachedMerkleTrieLoader, new NoOpBonsaiCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage), new NoOpTrieLogManager(), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); } /** diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProvider.java index d08821ca2ac..e4b7ea991f3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProvider.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -54,8 +55,11 @@ public BonsaiWorldStateProvider( super(worldStateKeyValueStorage, blockchain, maxLayersToLoad, pluginContext); this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader; provideCachedWorldStorageManager( - new BonsaiCachedWorldStorageManager(this, worldStateKeyValueStorage)); - loadPersistedState(new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration)); + new BonsaiCachedWorldStorageManager( + this, worldStateKeyValueStorage, this::cloneBonsaiWorldStateConfig)); + loadPersistedState( + new BonsaiWorldState( + this, worldStateKeyValueStorage, evmConfiguration, defaultWorldStateConfig)); } @VisibleForTesting @@ -69,14 +73,16 @@ public BonsaiWorldStateProvider( super(worldStateKeyValueStorage, blockchain, trieLogManager); this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader; provideCachedWorldStorageManager(bonsaiCachedWorldStorageManager); - loadPersistedState(new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration)); + loadPersistedState( + new BonsaiWorldState( + this, worldStateKeyValueStorage, evmConfiguration, defaultWorldStateConfig)); } public BonsaiCachedMerkleTrieLoader getCachedMerkleTrieLoader() { return bonsaiCachedMerkleTrieLoader; } - private BonsaiWorldStateKeyValueStorage getWorldStateKeyValueStorage() { + private BonsaiWorldStateKeyValueStorage getBonsaiWorldStateKeyValueStorage() { return (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage; } @@ -89,13 +95,13 @@ private BonsaiWorldStateKeyValueStorage getWorldStateKeyValueStorage() { public void prepareStateHealing(final Address address, final Bytes location) { final Set keysToDelete = new HashSet<>(); final BonsaiWorldStateKeyValueStorage.Updater updater = - getWorldStateKeyValueStorage().updater(); + getBonsaiWorldStateKeyValueStorage().updater(); final Hash accountHash = address.addressHash(); final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( (l, h) -> { final Optional node = - getWorldStateKeyValueStorage().getAccountStateTrieNode(l, h); + getBonsaiWorldStateKeyValueStorage().getAccountStateTrieNode(l, h); if (node.isPresent()) { keysToDelete.add(l); } @@ -115,7 +121,7 @@ public void prepareStateHealing(final Address address, final Bytes location) { new StoredMerklePatriciaTrie<>( (l, h) -> { Optional node = - getWorldStateKeyValueStorage() + getBonsaiWorldStateKeyValueStorage() .getAccountStorageTrieNode(accountHash, l, h); if (node.isPresent()) { keysToDelete.add(Bytes.concatenate(accountHash, l)); @@ -139,6 +145,10 @@ public void prepareStateHealing(final Address address, final Bytes location) { keysToDelete.forEach(updater::removeAccountStateTrieNode); updater.commit(); - getWorldStateKeyValueStorage().downgradeToPartialFlatDbMode(); + getBonsaiWorldStateKeyValueStorage().downgradeToPartialFlatDbMode(); + } + + private DiffBasedWorldStateConfig cloneBonsaiWorldStateConfig() { + return new DiffBasedWorldStateConfig(defaultWorldStateConfig); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedWorldStorageManager.java index cb081ea8785..60cf25e880c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedWorldStorageManager.java @@ -23,14 +23,18 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import java.util.function.Supplier; + public class BonsaiCachedWorldStorageManager extends DiffBasedCachedWorldStorageManager { public BonsaiCachedWorldStorageManager( final BonsaiWorldStateProvider archive, - final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) { - super(archive, worldStateKeyValueStorage); + final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage, + final Supplier defaultBonsaiWorldStateConfigSupplier) { + super(archive, worldStateKeyValueStorage, defaultBonsaiWorldStateConfigSupplier); } @Override @@ -41,7 +45,8 @@ public DiffBasedWorldState createWorldState( return new BonsaiWorldState( (BonsaiWorldStateProvider) archive, (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage, - evmConfiguration); + evmConfiguration, + defaultBonsaiWorldStateConfigSupplier.get()); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoOpBonsaiCachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoOpBonsaiCachedWorldStorageManager.java index daecab0e483..a054b437037 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoOpBonsaiCachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoOpBonsaiCachedWorldStorageManager.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import java.util.Optional; import java.util.function.Function; @@ -26,7 +27,7 @@ public class NoOpBonsaiCachedWorldStorageManager extends BonsaiCachedWorldStorag public NoOpBonsaiCachedWorldStorageManager( final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage) { - super(null, bonsaiWorldStateKeyValueStorage); + super(null, bonsaiWorldStateKeyValueStorage, DiffBasedWorldStateConfig::new); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java index 5934f88f2a2..2437118d640 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java @@ -203,6 +203,15 @@ public void onClearTrieLog() { } } + @Override + public void onClearTrie() { + try { + doClose(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override protected synchronized void doClose() throws Exception { if (!isClosedGet()) { 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 30b3d8440bc..ad838aa528d 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 @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrieException; +import org.hyperledger.besu.ethereum.trie.NoOpMerkleTrie; import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider; @@ -34,6 +35,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +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.trie.diffbased.common.worldview.accumulator.preload.StorageConsumingMap; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; @@ -63,13 +65,15 @@ public class BonsaiWorldState extends DiffBasedWorldState { public BonsaiWorldState( final BonsaiWorldStateProvider archive, final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, - final EvmConfiguration evmConfiguration) { + final EvmConfiguration evmConfiguration, + final DiffBasedWorldStateConfig diffBasedWorldStateConfig) { this( worldStateKeyValueStorage, archive.getCachedMerkleTrieLoader(), archive.getCachedWorldStorageManager(), archive.getTrieLogManager(), - evmConfiguration); + evmConfiguration, + diffBasedWorldStateConfig); } public BonsaiWorldState( @@ -77,21 +81,32 @@ public BonsaiWorldState( final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader, final DiffBasedCachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager, - final EvmConfiguration evmConfiguration) { - super(worldStateKeyValueStorage, cachedWorldStorageManager, trieLogManager); + final EvmConfiguration evmConfiguration, + final DiffBasedWorldStateConfig diffBasedWorldStateConfig) { + super( + worldStateKeyValueStorage, + cachedWorldStorageManager, + trieLogManager, + diffBasedWorldStateConfig); this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader; + this.worldStateKeyValueStorage = worldStateKeyValueStorage; this.setAccumulator( new BonsaiWorldStateUpdateAccumulator( this, (addr, value) -> bonsaiCachedMerkleTrieLoader.preLoadAccount( - worldStateKeyValueStorage, worldStateRootHash, addr), + getWorldStateStorage(), worldStateRootHash, addr), (addr, value) -> - bonsaiCachedMerkleTrieLoader.preLoadStorageSlot( + this.bonsaiCachedMerkleTrieLoader.preLoadStorageSlot( getWorldStateStorage(), addr, value), evmConfiguration)); } + @Override + public Optional getCode(@Nonnull final Address address, final Hash codeHash) { + return getWorldStateStorage().getCode(codeHash, address.addressHash()); + } + @Override public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { return (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage; @@ -129,7 +144,7 @@ private Hash internalCalculateRootHash( updateCode(maybeStateUpdater, worldStateUpdater); // next walk the account trie - final StoredMerklePatriciaTrie accountTrie = + final MerkleTrie accountTrie = createTrie( (location, hash) -> bonsaiCachedMerkleTrieLoader.getAccountStateTrieNode( @@ -157,7 +172,7 @@ private Hash internalCalculateRootHash( private void updateTheAccounts( final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater, - final StoredMerklePatriciaTrie accountTrie) { + final MerkleTrie accountTrie) { for (final Map.Entry> accountUpdate : worldStateUpdater.getAccountsToUpdate().entrySet()) { final Bytes accountKey = accountUpdate.getKey(); @@ -234,7 +249,7 @@ private void updateAccountStorageState( || worldStateUpdater.getStorageToClear().contains(updatedAddress)) ? Hash.EMPTY_TRIE_HASH : accountOriginal.getStorageRoot(); - final StoredMerklePatriciaTrie storageTrie = + final MerkleTrie storageTrie = createTrie( (location, key) -> bonsaiCachedMerkleTrieLoader.getAccountStorageTrieNode( @@ -277,8 +292,11 @@ private void updateAccountStorageState( (location, key, value) -> writeStorageTrieNode( bonsaiUpdater, updatedAddressHash, location, key, value))); - final Hash newStorageRoot = Hash.wrap(storageTrie.getRootHash()); - accountUpdated.setStorageRoot(newStorageRoot); + // only use storage root of the trie when trie is enabled + if (!worldStateConfig.isTrieDisabled()) { + final Hash newStorageRoot = Hash.wrap(storageTrie.getRootHash()); + accountUpdated.setStorageRoot(newStorageRoot); + } } } // for manicured tries and composting, trim and compost here @@ -347,13 +365,6 @@ public Hash frontierRootHash() { accumulator.copy()); } - @Override - public MutableWorldState freeze() { - this.isFrozen = true; - this.worldStateKeyValueStorage = new BonsaiWorldStateLayerStorage(getWorldStateStorage()); - return this; - } - @Override public Account get(final Address address) { return getWorldStateStorage() @@ -362,11 +373,6 @@ public Account get(final Address address) { .orElse(null); } - @Override - public Optional getCode(@Nonnull final Address address, final Hash codeHash) { - return getWorldStateStorage().getCode(codeHash, address.addressHash()); - } - protected Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { return getWorldStateStorage().getAccountStateTrieNode(location, nodeHash); } @@ -423,16 +429,26 @@ public UInt256 getPriorStorageValue(final Address address, final UInt256 storage @Override public Map getAllAccountStorage(final Address address, final Hash rootHash) { - final StoredMerklePatriciaTrie storageTrie = + final MerkleTrie storageTrie = createTrie( (location, key) -> getStorageTrieNode(address.addressHash(), location, key), rootHash); return storageTrie.entriesFrom(Bytes32.ZERO, Integer.MAX_VALUE); } - private StoredMerklePatriciaTrie createTrie( - final NodeLoader nodeLoader, final Bytes32 rootHash) { - return new StoredMerklePatriciaTrie<>( - nodeLoader, rootHash, Function.identity(), Function.identity()); + @Override + public MutableWorldState freeze() { + this.worldStateConfig.setFrozen(true); + this.worldStateKeyValueStorage = new BonsaiWorldStateLayerStorage(getWorldStateStorage()); + return this; + } + + private MerkleTrie createTrie(final NodeLoader nodeLoader, final Bytes32 rootHash) { + if (worldStateConfig.isTrieDisabled()) { + return new NoOpMerkleTrie<>(); + } else { + return new StoredMerklePatriciaTrie<>( + nodeLoader, rootHash, Function.identity(), Function.identity()); + } } protected Hash hashAndSavePreImage(final Bytes value) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java index ad7b06b149a..857ec0b079d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +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.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; @@ -54,6 +55,7 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive { protected DiffBasedWorldState persistedState; protected final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage; + protected final DiffBasedWorldStateConfig defaultWorldStateConfig; public DiffBasedWorldStateProvider( final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage, @@ -70,6 +72,7 @@ public DiffBasedWorldStateProvider( maxLayersToLoad.orElse(DiffBasedCachedWorldStorageManager.RETAINED_LAYERS), pluginContext); this.blockchain = blockchain; + this.defaultWorldStateConfig = new DiffBasedWorldStateConfig(); } public DiffBasedWorldStateProvider( @@ -81,6 +84,7 @@ public DiffBasedWorldStateProvider( // TODO: de-dup constructors this.trieLogManager = trieLogManager; this.blockchain = blockchain; + this.defaultWorldStateConfig = new DiffBasedWorldStateConfig(); } protected void provideCachedWorldStorageManager( @@ -252,6 +256,19 @@ public MutableWorldState getMutable() { return persistedState; } + public DiffBasedWorldStateConfig getDefaultWorldStateConfig() { + return defaultWorldStateConfig; + } + + public void disableTrie() { + defaultWorldStateConfig.setTrieDisabled(true); + worldStateKeyValueStorage.clearTrie(); + } + + public DiffBasedWorldStateKeyValueStorage getWorldStateKeyValueStorage() { + return worldStateKeyValueStorage; + } + public TrieLogManager getTrieLogManager() { return trieLogManager; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/StorageSubscriber.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/StorageSubscriber.java index 51ab65bd16c..258df5c5b9c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/StorageSubscriber.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/StorageSubscriber.java @@ -21,5 +21,7 @@ default void onClearFlatDatabaseStorage() {} default void onClearTrieLog() {} + default void onClearTrie() {} + default void onCloseStorage() {} } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldStorageManager.java index 8ead22bf5bf..160c7ac1e3e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldStorageManager.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedLayeredWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.evm.internal.EvmConfiguration; import java.util.ArrayList; @@ -33,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.function.Supplier; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; @@ -46,6 +48,7 @@ public abstract class DiffBasedCachedWorldStorageManager implements StorageSubsc LoggerFactory.getLogger(DiffBasedCachedWorldStorageManager.class); private final DiffBasedWorldStateProvider archive; private final EvmConfiguration evmConfiguration; + protected final Supplier defaultBonsaiWorldStateConfigSupplier; private final Cache stateRootToBlockHeaderCache = Caffeine.newBuilder() .maximumSize(RETAINED_LAYERS) @@ -59,18 +62,26 @@ private DiffBasedCachedWorldStorageManager( final DiffBasedWorldStateProvider archive, final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage, final Map cachedWorldStatesByHash, - final EvmConfiguration evmConfiguration) { + final EvmConfiguration evmConfiguration, + final Supplier defaultBonsaiWorldStateConfigSupplier) { worldStateKeyValueStorage.subscribe(this); this.rootWorldStateStorage = worldStateKeyValueStorage; this.cachedWorldStatesByHash = cachedWorldStatesByHash; this.archive = archive; this.evmConfiguration = evmConfiguration; + this.defaultBonsaiWorldStateConfigSupplier = defaultBonsaiWorldStateConfigSupplier; } public DiffBasedCachedWorldStorageManager( final DiffBasedWorldStateProvider archive, - final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) { - this(archive, worldStateKeyValueStorage, new ConcurrentHashMap<>(), EvmConfiguration.DEFAULT); + final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage, + final Supplier defaultBonsaiWorldStateConfigSupplier) { + this( + archive, + worldStateKeyValueStorage, + new ConcurrentHashMap<>(), + EvmConfiguration.DEFAULT, + defaultBonsaiWorldStateConfigSupplier); } public synchronized void addCachedLayer( @@ -263,6 +274,11 @@ public void onClearTrieLog() { this.cachedWorldStatesByHash.clear(); } + @Override + public void onClearTrie() { + this.cachedWorldStatesByHash.clear(); + } + @Override public void onCloseStorage() { this.cachedWorldStatesByHash.clear(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java index af568035451..84441ca05fb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java @@ -174,6 +174,11 @@ public void clearTrieLog() { trieLogStorage.clear(); } + public void clearTrie() { + subscribers.forEach(StorageSubscriber::onClearTrie); + composedWorldStateStorage.clear(TRIE_BRANCH_STORAGE); + } + public void clearFlatDatabase() { subscribers.forEach(StorageSubscriber::onClearFlatDatabaseStorage); getFlatDbStrategy().resetOnResync(composedWorldStateStorage); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java index 9ae6cb38f81..70d45f546db 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java @@ -34,6 +34,7 @@ import java.util.stream.LongStream; import java.util.stream.Stream; +import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,15 +148,46 @@ private TrieLogFactory setupTrieLogFactory(final BesuContext pluginContext) { trieLogService.getObservers().forEach(trieLogObservers::subscribe); // return the TrieLogFactory implementation from the TrieLogService - return trieLogService.getTrieLogFactory(); - } else { - // Otherwise default to TrieLogFactoryImpl - return new TrieLogFactoryImpl(); + if (trieLogService.getTrieLogFactory().isPresent()) { + return trieLogService.getTrieLogFactory().get(); + } } + // Otherwise default to TrieLogFactoryImpl + return new TrieLogFactoryImpl(); } private TrieLogProvider getTrieLogProvider() { return new TrieLogProvider() { + @Override + public Optional getRawTrieLogLayer(final Hash blockHash) { + return rootWorldStateStorage.getTrieLog(blockHash).map(Bytes::wrap); + } + + @Override + public Optional getRawTrieLogLayer(final long blockNumber) { + return TrieLogManager.this + .blockchain + .getBlockHeader(blockNumber) + .map(BlockHeader::getHash) + .flatMap(this::getRawTrieLogLayer); + } + + @Override + public void saveRawTrieLogLayer( + final Hash blockHash, final long blockNumber, final Bytes trieLog) { + final DiffBasedWorldStateKeyValueStorage.Updater updater = rootWorldStateStorage.updater(); + updater + .getTrieLogStorageTransaction() + .put(blockHash.toArrayUnsafe(), trieLog.toArrayUnsafe()); + updater.commit(); + // TODO maybe find a way to have a clean and complete trielog for observers + trieLogObservers.forEach( + o -> + o.onTrieLogAdded( + new TrieLogAddedEvent( + new TrieLogLayer().setBlockHash(blockHash).setBlockNumber(blockNumber)))); + } + @Override public Optional getTrieLogLayer(final Hash blockHash) { return TrieLogManager.this.getTrieLogLayer(blockHash); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java index db536cbc7a7..76a8fbd6377 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java @@ -60,12 +60,13 @@ public abstract class DiffBasedWorldState protected Hash worldStateRootHash; protected Hash worldStateBlockHash; - protected boolean isFrozen; + protected DiffBasedWorldStateConfig worldStateConfig; protected DiffBasedWorldState( final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage, final DiffBasedCachedWorldStorageManager cachedWorldStorageManager, - final TrieLogManager trieLogManager) { + final TrieLogManager trieLogManager, + final DiffBasedWorldStateConfig diffBasedWorldStateConfig) { this.worldStateKeyValueStorage = worldStateKeyValueStorage; this.worldStateRootHash = Hash.wrap( @@ -76,11 +77,12 @@ protected DiffBasedWorldState( Bytes32.wrap(worldStateKeyValueStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); this.cachedWorldStorageManager = cachedWorldStorageManager; this.trieLogManager = trieLogManager; + this.worldStateConfig = diffBasedWorldStateConfig; } /** * Having a protected method to override the accumulator solves the chicken-egg problem of needing - * a worldstate reference (this) when construction the Accumulator. + * a worldstate reference (this) when constructing the Accumulator. * * @param accumulator accumulator to use. */ @@ -134,6 +136,15 @@ public DiffBasedWorldStateUpdateAccumulator getAccumulator() { return accumulator; } + protected Hash unsafeRootHashUpdate( + final BlockHeader blockHeader, + final DiffBasedWorldStateKeyValueStorage.Updater stateUpdater) { + // calling calculateRootHash in order to update the state + calculateRootHash( + worldStateConfig.isFrozen() ? Optional.empty() : Optional.of(stateUpdater), accumulator); + return blockHeader.getStateRoot(); + } + @Override public void persist(final BlockHeader blockHeader) { final Optional maybeBlockHeader = Optional.ofNullable(blockHeader); @@ -151,19 +162,32 @@ public void persist(final BlockHeader blockHeader) { Runnable saveTrieLog = () -> {}; try { - final Hash newWorldStateRootHash = - calculateRootHash(isFrozen ? Optional.empty() : Optional.of(stateUpdater), accumulator); + final Hash calculatedRootHash; + + if (blockHeader == null || !worldStateConfig.isTrieDisabled()) { + calculatedRootHash = + calculateRootHash( + worldStateConfig.isFrozen() ? Optional.empty() : Optional.of(stateUpdater), + accumulator); + } else { + // if the trie is disabled, we cannot calculate the state root, so we directly use the root + // of the block. It's important to understand that in all networks, + // the state root must be validated independently and the block should not be trusted + // implicitly. This mode + // can be used in cases where Besu would just be a follower of another trusted client. + calculatedRootHash = unsafeRootHashUpdate(blockHeader, stateUpdater); + } // if we are persisted with a block header, and the prior state is the parent // then persist the TrieLog for that transition. // If specified but not a direct descendant simply store the new block hash. if (blockHeader != null) { - verifyWorldStateRoot(newWorldStateRootHash, blockHeader); + verifyWorldStateRoot(calculatedRootHash, blockHeader); saveTrieLog = () -> { - trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this); + trieLogManager.saveTrieLog(localCopy, calculatedRootHash, blockHeader, this); // not save a frozen state in the cache - if (!isFrozen) { - cachedWorldStorageManager.addCachedLayer(blockHeader, newWorldStateRootHash, this); + if (!worldStateConfig.isFrozen()) { + cachedWorldStorageManager.addCachedLayer(blockHeader, calculatedRootHash, this); } }; @@ -178,8 +202,8 @@ public void persist(final BlockHeader blockHeader) { stateUpdater .getWorldStateTransaction() - .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, newWorldStateRootHash.toArrayUnsafe()); - worldStateRootHash = newWorldStateRootHash; + .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, calculatedRootHash.toArrayUnsafe()); + worldStateRootHash = calculatedRootHash; success = true; } finally { if (success) { @@ -194,7 +218,7 @@ public void persist(final BlockHeader blockHeader) { } protected void verifyWorldStateRoot(final Hash calculatedStateRoot, final BlockHeader header) { - if (!calculatedStateRoot.equals(header.getStateRoot())) { + if (!worldStateConfig.isTrieDisabled() && !calculatedStateRoot.equals(header.getStateRoot())) { throw new RuntimeException( "World State Root does not match expected value, header " + header.getStateRoot().toHexString() @@ -210,7 +234,7 @@ public WorldUpdater updater() { @Override public Hash rootHash() { - if (isFrozen && accumulator.isAccumulatorStateChanged()) { + if (worldStateConfig.isFrozen() && accumulator.isAccumulatorStateChanged()) { worldStateRootHash = calculateRootHash(Optional.empty(), accumulator.copy()); accumulator.resetAccumulatorStateChanged(); } @@ -285,7 +309,7 @@ public void close() { try { if (!isPersisted()) { this.worldStateKeyValueStorage.close(); - if (isFrozen) { + if (worldStateConfig.isFrozen()) { closeFrozenStorage(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldStateConfig.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldStateConfig.java new file mode 100644 index 00000000000..cab7f3f8736 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldStateConfig.java @@ -0,0 +1,79 @@ +/* + * 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.common.worldview; + +public class DiffBasedWorldStateConfig { + + private boolean isFrozen; + + private boolean isTrieDisabled; + + public DiffBasedWorldStateConfig() { + this(false, false); + } + + public DiffBasedWorldStateConfig(final boolean isTrieDisabled) { + this(false, isTrieDisabled); + } + + public DiffBasedWorldStateConfig(final DiffBasedWorldStateConfig config) { + this(config.isFrozen(), config.isTrieDisabled()); + } + + public DiffBasedWorldStateConfig(final boolean isFrozen, final boolean isTrieDisabled) { + this.isFrozen = isFrozen; + this.isTrieDisabled = isTrieDisabled; + } + + /** + * Checks if the world state is frozen. When the world state is frozen, it cannot mutate. + * + * @return true if the world state is frozen, false otherwise. + */ + public boolean isFrozen() { + return isFrozen; + } + + /** + * Sets the frozen status of the world state. When the world state is frozen, it cannot mutate. + * + * @param frozen the new frozen status to set. + */ + public void setFrozen(final boolean frozen) { + isFrozen = frozen; + } + + /** + * Checks if the trie is disabled for the world state. When the trie is disabled, the world state + * will only work with the flat database and not the trie. In this mode, it's impossible to verify + * the state root. + * + * @return true if the trie is disabled, false otherwise. + */ + public boolean isTrieDisabled() { + return isTrieDisabled; + } + + /** + * Sets the disabled status of the trie for the world state. When the trie is disabled, the world + * state will only work with the flat database and not the trie. In this mode, it's impossible to + * verify the state root. + * + * @param trieDisabled the new disabled status to set for the trie. + */ + public void setTrieDisabled(final boolean trieDisabled) { + isTrieDisabled = trieDisabled; + } +} 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 6af78e59903..6c84b29b478 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 @@ -46,6 +46,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider; 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.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; @@ -100,7 +101,8 @@ class BlockImportExceptionHandlingTest { (BonsaiWorldStateProvider) worldStateArchive, (BonsaiWorldStateKeyValueStorage) worldStateStorageCoordinator.worldStateKeyValueStorage(), - EvmConfiguration.DEFAULT)); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig())); private final BadBlockManager badBlockManager = new BadBlockManager(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/ChainDataPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/ChainDataPrunerTest.java index 78ab15eb686..556e4edefc7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/ChainDataPrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/ChainDataPrunerTest.java @@ -48,6 +48,7 @@ public void singleChainPruning() { new ChainDataPrunerStorage(new InMemoryKeyValueStorage()), 512, 0, + // completed new BlockingExecutor()); Block genesisBlock = gen.genesisBlock(); final MutableBlockchain blockchain = @@ -87,6 +88,7 @@ public void forkPruning() { new ChainDataPrunerStorage(new InMemoryKeyValueStorage()), 512, 0, + // completed new BlockingExecutor()); Block genesisBlock = gen.genesisBlock(); final MutableBlockchain blockchain = 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 0dee834f1cb..d9b9d5d1955 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 @@ -199,6 +199,16 @@ protected StorageProvider createKeyValueStorageProvider() { .withCommonConfiguration( new BesuConfiguration() { + @Override + public Optional getRpcHttpHost() { + return Optional.empty(); + } + + @Override + public Optional getRpcHttpPort() { + return Optional.empty(); + } + @Override public Path getStoragePath() { return tempData.resolve("database"); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java index 5c0dbbf7259..e43d464474c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java @@ -32,6 +32,7 @@ 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.trielog.TrieLogLayer; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -162,7 +163,8 @@ void simpleRollForwardTest() { archive, new BonsaiWorldStateKeyValueStorage( provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final WorldUpdater updater = worldState.updater(); final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); @@ -178,7 +180,8 @@ provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFI secondProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final BonsaiWorldStateUpdateAccumulator secondUpdater = (BonsaiWorldStateUpdateAccumulator) secondWorldState.updater(); @@ -210,7 +213,8 @@ void rollForwardTwice() { archive, new BonsaiWorldStateKeyValueStorage( provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final WorldUpdater updater = worldState.updater(); final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); @@ -234,7 +238,8 @@ provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFI secondProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final BonsaiWorldStateUpdateAccumulator secondUpdater = (BonsaiWorldStateUpdateAccumulator) secondWorldState.updater(); @@ -267,7 +272,8 @@ void rollBackOnce() { archive, new BonsaiWorldStateKeyValueStorage( provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final WorldUpdater updater = worldState.updater(); final MutableAccount mutableAccount = updater.createAccount(addressOne, 1, Wei.of(1L)); @@ -298,7 +304,8 @@ provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFI secondProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final WorldUpdater secondUpdater = secondWorldState.updater(); final MutableAccount secondMutableAccount = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/RollingImport.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/RollingImport.java index 0c2c1898927..09e21138fd3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/RollingImport.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/RollingImport.java @@ -28,6 +28,7 @@ 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.trielog.TrieLogLayer; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -57,7 +58,8 @@ public static void main(final String[] arg) throws IOException { archive, new BonsaiWorldStateKeyValueStorage( provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); final SegmentedInMemoryKeyValueStorage worldStateKeyValueStorage = (SegmentedInMemoryKeyValueStorage) provider.getStorageBySegmentIdentifiers( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateTest.java index 0757b40dbbb..b342172b1ba 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateTest.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldStateConfig; import org.hyperledger.besu.evm.internal.EvmConfiguration; import java.util.HashMap; @@ -61,7 +62,8 @@ void setup() { new BonsaiWorldState( InMemoryKeyValueStorageProvider.createBonsaiInMemoryWorldStateArchive(blockchain), bonsaiWorldStateKeyValueStorage, - EvmConfiguration.DEFAULT); + EvmConfiguration.DEFAULT, + new DiffBasedWorldStateConfig()); } @ParameterizedTest diff --git a/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java b/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java index 1fc9046ec72..04d4af81a94 100644 --- a/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java +++ b/ethereum/eth/src/jmh/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldStateDownloaderBenchmark.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; @@ -165,8 +164,7 @@ public Optional downloadWorldState() { private StorageProvider createKeyValueStorageProvider(final Path dataDir, final Path dbDir) { final var besuConfiguration = new BesuConfigurationImpl(); - besuConfiguration.init( - dataDir, dbDir, DataStorageConfiguration.DEFAULT_CONFIG, MiningParameters.newDefault()); + besuConfiguration.init(dataDir, dbDir, DataStorageConfiguration.DEFAULT_CONFIG); return new KeyValueStorageProviderBuilder() .withStorageFactory( new RocksDBKeyValueStorageFactory( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/AbstractSyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/AbstractSyncTargetManager.java index 9c6b9327e4b..f5b5f978cb3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/AbstractSyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/AbstractSyncTargetManager.java @@ -28,6 +28,7 @@ import java.time.Duration; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +37,8 @@ public abstract class AbstractSyncTargetManager { private static final Logger LOG = LoggerFactory.getLogger(AbstractSyncTargetManager.class); + private final AtomicBoolean cancelled = new AtomicBoolean(false); + private final SynchronizerConfiguration config; private final ProtocolSchedule protocolSchedule; private final ProtocolContext protocolContext; @@ -56,6 +59,9 @@ protected AbstractSyncTargetManager( } public CompletableFuture findSyncTarget() { + if (isCancelled()) { + return completedFuture(null); + } return selectBestAvailableSyncTarget() .thenCompose( maybeBestPeer -> { @@ -99,6 +105,10 @@ public CompletableFuture findSyncTarget() { }); } + public synchronized void cancel() { + cancelled.set(true); + } + protected Optional finalizeSelectedSyncTarget(final SyncTarget syncTarget) { return Optional.of(syncTarget); } @@ -115,5 +125,9 @@ private CompletableFuture waitForNewPeer() { .timeout(WaitForPeerTask.create(ethContext, metricsSystem), Duration.ofSeconds(5)); } + private boolean isCancelled() { + return cancelled.get(); + } + public abstract boolean shouldContinueDownloading(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java index e40b28efad6..bfec1435ce4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/PipelineChainDownloader.java @@ -85,6 +85,7 @@ public CompletableFuture start() { @Override public synchronized void cancel() { cancelled.set(true); + syncTargetManager.cancel(); if (currentDownloadPipeline != null) { currentDownloadPipeline.abort(); } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommandOptionsModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommandOptionsModule.java index 017320aca1a..fe229dc3cf3 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommandOptionsModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommandOptionsModule.java @@ -87,7 +87,7 @@ String provideKeyValueStorageName() { @Singleton BesuConfiguration provideBesuConfiguration() { final var besuConfiguration = new BesuConfigurationImpl(); - besuConfiguration.init(dataPath, dataPath.resolve(BesuController.DATABASE_PATH), null, null); + besuConfiguration.init(dataPath, dataPath.resolve(BesuController.DATABASE_PATH), null); return besuConfiguration; } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index 8eb07e43385..5d0fee18453 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -260,6 +260,7 @@ public CompletableFuture stop() { l.clear(); }); inflightInteractions.clear(); + recursivePeerRefreshState.cancel(); return CompletableFuture.completedFuture(null); } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java index 0f3073dfd19..3329dad4ce8 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java @@ -105,6 +105,10 @@ private void addInitialPeers(final List initialPeers) { } private void bondingInitiateRound() { + if (!iterativeSearchInProgress) { + // cancelled so we can ignore + return; + } currentRoundTimeout.ifPresent(RoundTimeout::cancelTimeout); final List candidates = bondingRoundCandidates(); if (candidates.isEmpty()) { @@ -137,6 +141,10 @@ private void performIfNotCancelled(final Runnable action, final AtomicBoolean ca } private void bondingCancelOutstandingRequests() { + if (!iterativeSearchInProgress) { + // cancelled so we can ignore + return; + } LOG.debug("Bonding round timed out"); for (final Map.Entry entry : oneTrueMap.entrySet()) { final MetadataPeer metadataPeer = entry.getValue(); @@ -149,6 +157,10 @@ private void bondingCancelOutstandingRequests() { } private void neighboursInitiateRound() { + if (!iterativeSearchInProgress) { + // cancelled so we can ignore + return; + } currentRoundTimeout.ifPresent(RoundTimeout::cancelTimeout); final List candidates = neighboursRoundCandidates(); if (candidates.isEmpty() || reachedMaximumNumberOfRounds()) { @@ -172,6 +184,10 @@ private void neighboursInitiateRound() { } private void neighboursCancelOutstandingRequests() { + if (!iterativeSearchInProgress) { + // cancelled so we can ignore + return; + } LOG.debug("Neighbours round timed out"); for (final Map.Entry entry : oneTrueMap.entrySet()) { final MetadataPeer metadataPeer = entry.getValue(); @@ -218,6 +234,10 @@ void onNeighboursReceived(final DiscoveryPeer peer, final List pe } void onBondingComplete(final DiscoveryPeer peer) { + if (!iterativeSearchInProgress) { + // cancelled so we can ignore + return; + } final MetadataPeer iterationParticipant = oneTrueMap.get(peer.getId()); if (iterationParticipant == null) { return; diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java index 8acdea1170a..e374f5c020f 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogAddedEvent; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +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; @@ -66,7 +67,8 @@ protected BonsaiReferenceTestWorldState( bonsaiCachedMerkleTrieLoader, cachedWorldStorageManager, trieLogManager, - evmConfiguration); + evmConfiguration, + new DiffBasedWorldStateConfig()); this.refTestStorage = worldStateKeyValueStorage; this.preImageProxy = preImageProxy; this.evmConfiguration = evmConfiguration; @@ -194,7 +196,8 @@ private BonsaiWorldState createBonsaiWorldState(final boolean isFrozen) { bonsaiCachedMerkleTrieLoader, cachedWorldStorageManager, trieLogManager, - evmConfiguration); + evmConfiguration, + new DiffBasedWorldStateConfig()); if (isFrozen) { bonsaiWorldState.freeze(); // freeze state } diff --git a/ethereum/trie/src/main/java/org/hyperledger/besu/ethereum/trie/NoOpMerkleTrie.java b/ethereum/trie/src/main/java/org/hyperledger/besu/ethereum/trie/NoOpMerkleTrie.java new file mode 100644 index 00000000000..53d0ac5b58a --- /dev/null +++ b/ethereum/trie/src/main/java/org/hyperledger/besu/ethereum/trie/NoOpMerkleTrie.java @@ -0,0 +1,123 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +/** + * A noop {@link MerkleTrie}. + * + * @param The type of values of this trie. + */ +public class NoOpMerkleTrie implements MerkleTrie { + + public NoOpMerkleTrie() {} + + @Override + public Optional get(final K key) { + return Optional.empty(); + } + + @Override + public Optional getPath(final K path) { + return Optional.empty(); + } + + @Override + public Proof getValueWithProof(final K key) { + return new Proof<>(Optional.empty(), new ArrayList<>()); + } + + @Override + public void put(final K key, final V value) { + // noop + } + + @Override + public void putPath(final K path, final V value) { + // noop + } + + @Override + public void put(final K key, final PathNodeVisitor putVisitor) { + // noop + } + + @Override + public void remove(final K key) { + // noop + } + + @Override + public void removePath(final K path, final PathNodeVisitor removeVisitor) { + // noop + } + + @Override + public Bytes32 getRootHash() { + return EMPTY_TRIE_NODE_HASH; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getRootHash() + "]"; + } + + @Override + public void commit(final NodeUpdater nodeUpdater) { + // Nothing to do here + } + + @Override + public void commit(final NodeUpdater nodeUpdater, final CommitVisitor commitVisitor) { + // Nothing to do here + } + + @Override + public Map entriesFrom(final Bytes32 startKeyHash, final int limit) { + return new HashMap<>(); + } + + @Override + public Map entriesFrom(final Function, Map> handler) { + return new HashMap<>(); + } + + @Override + public void visitAll(final Consumer> nodeConsumer) { + // noop + } + + @Override + public CompletableFuture visitAll( + final Consumer> nodeConsumer, final ExecutorService executorService) { + return CompletableFuture.completedFuture(null); + } + + @Override + public void visitLeafs(final TrieIterator.LeafHandler handler) { + // nopop + } +} diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index f61fe316bf3..e38237d7c3f 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -70,7 +70,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'xU0LMvStiFihBKBxkfNHB7oIg0PUHWkPuv2yt1GVC94=' + knownHash = 'wMhttXj2aWFgpN9msxHz/FwQVovpYRxNysnZEpwZYxg=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java index 9c9dc44bf02..952f1fb074d 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java @@ -63,6 +63,9 @@ default void beforeExternalServices() {} */ void start(); + /** Hook to execute plugin setup code after external services */ + default void afterExternalServicePostMainLoop() {} + /** * Called when the plugin is being reloaded. This method will be called through a dedicated JSON * RPC endpoint. If not overridden this method does nothing for convenience. The plugin should diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java index ca92a12430f..c10a697384f 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java @@ -20,10 +20,25 @@ import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.nio.file.Path; +import java.util.Optional; /** Generally useful configuration provided by Besu. */ public interface BesuConfiguration extends BesuService { + /** + * Get the configured RPC http host. + * + * @return the configured RPC http host. + */ + Optional getRpcHttpHost(); + + /** + * Get the configured RPC http port. + * + * @return the configured RPC http port. + */ + Optional getRpcHttpPort(); + /** * Location of the working directory of the storage in the file system running the client. * diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java index 911eff3b593..ab9c4eb782d 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java @@ -93,6 +93,14 @@ public interface BesuEvents extends BesuService { */ void removeBlockReorgListener(long listenerIdentifier); + /** + * Add an initial sync completion listener. + * + * @param listener to subscribe to initial sync completion events + * @return id of listener subscription + */ + long addInitialSyncCompletionListener(final InitialSyncCompletionListener listener); + /** * Add a listener watching new transactions added to the node. * diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java index af6d14f546c..69a2e6a8220 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java @@ -17,9 +17,12 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.TransactionReceipt; +import java.util.List; import java.util.Optional; /** A service that plugins can use to query blocks by number */ @@ -40,6 +43,23 @@ public interface BlockchainService extends BesuService { */ Hash getChainHeadHash(); + /** + * Get the receipts for a block by block hash + * + * @param blockHash the block hash + * @return the transaction receipts + */ + Optional> getReceiptsByBlockHash(Hash blockHash); + + /** + * Store a block + * + * @param blockHeader the block header + * @param blockBody the block body + * @param receipts the transaction receipts + */ + void storeBlock(BlockHeader blockHeader, BlockBody blockBody, List receipts); + /** * Get the block header of the chain head * @@ -53,4 +73,18 @@ public interface BlockchainService extends BesuService { * @return base fee of the next block or empty if the fee market does not support base fee */ Optional getNextBlockBaseFee(); + + /** + * Get the block hash of the safe block + * + * @return the block hash of the safe block + */ + Optional getSafeBlock(); + + /** + * Get the block hash of the finalized block + * + * @return the block hash of the finalized block + */ + Optional getFinalizedBlock(); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TrieLogService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TrieLogService.java index 2c5c38c5498..5230d6a6642 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TrieLogService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TrieLogService.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.plugin.services.trielogs.TrieLogProvider; import java.util.List; +import java.util.Optional; /** * A service interface for registering observers for trie log events. @@ -39,7 +40,7 @@ public interface TrieLogService extends BesuService { * * @return the TrieLogFactory implementation */ - TrieLogFactory getTrieLogFactory(); + Optional getTrieLogFactory(); /** * Configure a TrieLogProvider implementation to use for retrieving stored TrieLogs. diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/p2p/P2PService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/p2p/P2PService.java new file mode 100644 index 00000000000..0e9e46e799a --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/p2p/P2PService.java @@ -0,0 +1,27 @@ +/* + * 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.plugin.services.p2p; + +import org.hyperledger.besu.plugin.services.BesuService; + +/** Service to enable and disable P2P service. */ +public interface P2PService extends BesuService { + + /** Enables P2P discovery. */ + void enableDiscovery(); + + /** Disables P2P discovery. */ + void disableDiscovery(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/rlp/RlpConverterService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/rlp/RlpConverterService.java new file mode 100644 index 00000000000..016fab7fa46 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/rlp/RlpConverterService.java @@ -0,0 +1,74 @@ +/* + * 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.plugin.services.rlp; + +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.TransactionReceipt; +import org.hyperledger.besu.plugin.services.BesuService; + +import org.apache.tuweni.bytes.Bytes; + +/** RLP Serialiaztion/Deserialization service. */ +public interface RlpConverterService extends BesuService { + + /** + * Builds a block header from RLP. + * + * @param rlp the RLP to build the block header from. + * @return the block header. + */ + BlockHeader buildHeaderFromRlp(final Bytes rlp); + + /** + * Builds a block body from RLP. + * + * @param rlp the RLP to build the block body from. + * @return the block body. + */ + BlockBody buildBodyFromRlp(final Bytes rlp); + + /** + * Builds a transaction receipt from RLP. + * + * @param rlp the RLP to build the transaction receipt from. + * @return the transaction receipt. + */ + TransactionReceipt buildReceiptFromRlp(final Bytes rlp); + + /** + * RLP encodes a block header. + * + * @param blockHeader the block header to build RLP from. + * @return the RLP. + */ + Bytes buildRlpFromHeader(final BlockHeader blockHeader); + + /** + * RLP encodes a block body. + * + * @param blockBody the block body to build RLP from. + * @return the RLP. + */ + Bytes buildRlpFromBody(final BlockBody blockBody); + + /** + * RLP encodes a transaction receipt. + * + * @param receipt the transaction receipt to build RLP from. + * @return the RLP. + */ + Bytes buildRlpFromReceipt(final TransactionReceipt receipt); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/SynchronizationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/SynchronizationService.java new file mode 100644 index 00000000000..ad9682429d0 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/SynchronizationService.java @@ -0,0 +1,62 @@ +/* + * 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.plugin.services.sync; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.services.BesuService; + +/** Synchronization service wraps the sync state and sync event lifecycle. */ +public interface SynchronizationService extends BesuService { + + /** + * Enables P2P discovery. + * + * @param head the head of the chain. + * @param safeBlock the safe block. + * @param finalizedBlock the finalized block. + */ + void fireNewUnverifiedForkchoiceEvent(Hash head, Hash safeBlock, Hash finalizedBlock); + + /** + * Set the head of the chain. + * + * @param blockHeader the block header + * @param blockBody the block body + * @return true if the head was set, false otherwise. + */ + boolean setHead(final BlockHeader blockHeader, final BlockBody blockBody); + + /** + * Adds the block header and body to the head of the chain directly, without using a block + * importer or validation. + * + * @param blockHeader the block header + * @param blockBody the block body + * @return true if the head was set, false otherwise. + */ + boolean setHeadUnsafe(BlockHeader blockHeader, BlockBody blockBody); + + /** + * Returns whether the initial chain and worldstate sync is complete. + * + * @return true if the initial sync phase is done, false otherwise. + */ + boolean isInitialSyncPhaseDone(); + + /** Disables the worldstate trie for update. */ + void disableWorldStateTrie(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/WorldStateConfiguration.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/WorldStateConfiguration.java new file mode 100644 index 00000000000..3f66ffb86e1 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/sync/WorldStateConfiguration.java @@ -0,0 +1,26 @@ +/* + * 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.plugin.services.sync; + +/** interface for worldstate configuration * */ +public interface WorldStateConfiguration { + + /** + * Returns whether the trie is disabled. + * + * @return true if the trie is disabled, false otherwise. + */ + boolean isTrieDisabled(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/transactionpool/TransactionPoolService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/transactionpool/TransactionPoolService.java new file mode 100644 index 00000000000..01b1f5768b3 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/transactionpool/TransactionPoolService.java @@ -0,0 +1,26 @@ +/* + * 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.plugin.services.transactionpool; + +import org.hyperledger.besu.plugin.services.BesuService; + +/** Service to enable and disable the transaction pool. */ +public interface TransactionPoolService extends BesuService { + /** Enables the transaction pool. */ + void disableTransactionPool(); + + /** Disables the transaction pool. */ + void enableTransactionPool(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/trielogs/TrieLogProvider.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/trielogs/TrieLogProvider.java index 86a9906cf08..b20e73283cb 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/trielogs/TrieLogProvider.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/trielogs/TrieLogProvider.java @@ -19,8 +19,19 @@ import java.util.List; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; + /** Trielog provider interface for a given block hash. */ public interface TrieLogProvider { + /** + * Saves the TrieLog layer for the given block hash. + * + * @param blockHash the block hash + * @param blockNumber the block number + * @param trieLog the associated TrieLog layer + */ + void saveRawTrieLogLayer(final Hash blockHash, final long blockNumber, final Bytes trieLog); + /** * Returns the TrieLog layer for the given block hash. * @@ -30,6 +41,14 @@ public interface TrieLogProvider { */ > Optional getTrieLogLayer(final Hash blockHash); + /** + * Get the raw TrieLog layer for the given block hash. + * + * @param blockHash the block hash + * @return the raw TrieLog layer bytes for the given block hash + */ + Optional getRawTrieLogLayer(final Hash blockHash); + /** * Returns the TrieLog layer for the given block number. * @@ -39,6 +58,14 @@ public interface TrieLogProvider { */ > Optional getTrieLogLayer(final long blockNumber); + /** + * Get the raw TrieLog layer for the given block number. + * + * @param blockNumber the block number + * @return the raw TrieLog layer bytes for the given block number + */ + Optional getRawTrieLogLayer(final long blockNumber); + /** * Returns the TrieLog layers for the given block number range. *