From 2360908cf5cdaee270bc06eeaf43442687df352f Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Fri, 8 Mar 2024 20:57:10 +0100 Subject: [PATCH] worldstate refactor (#6209) * worldstate storage refactor Signed-off-by: Karim TAAM Signed-off-by: Gabriel Fukushima Co-authored-by: Gabriel Fukushima --- .../cli/subcommands/operator/BackupState.java | 10 +- .../subcommands/operator/RestoreState.java | 14 +- .../controller/BesuControllerBuilder.java | 46 +++--- .../TransitionBesuControllerBuilder.java | 6 +- .../controller/BesuControllerBuilderTest.java | 39 +++-- .../MergeBesuControllerBuilderTest.java | 21 ++- .../QbftBesuControllerBuilderTest.java | 21 ++- .../api/query/StateBackupService.java | 16 +- .../forest/pruner/PrunerIntegrationTest.java | 12 +- .../besu/ethereum/core/PrivacyParameters.java | 6 +- .../storage/PrivacyStorageProvider.java | 7 +- .../PrivacyKeyValueStorageProvider.java | 10 +- .../proof/WorldStateProofProvider.java | 14 +- .../ethereum/storage/StorageProvider.java | 9 +- .../keyvalue/KeyValueStorageProvider.java | 12 +- .../trie/bonsai/BonsaiWorldStateProvider.java | 41 +++-- .../bonsai/cache/CachedBonsaiWorldView.java | 18 +- .../bonsai/cache/CachedMerkleTrieLoader.java | 28 ++-- .../cache/CachedWorldStorageManager.java | 10 +- ...nsaiSnapshotWorldStateKeyValueStorage.java | 11 +- .../BonsaiWorldStateKeyValueStorage.java | 95 +++-------- .../trie/bonsai/trielog/TrieLogManager.java | 8 +- .../bonsai/worldview/BonsaiWorldState.java | 72 ++++---- .../trie/forest/ForestWorldStateArchive.java | 24 +-- .../trie/forest/pruner/MarkSweepPruner.java | 37 +++-- .../ForestWorldStateKeyValueStorage.java | 78 +++------ .../worldview/ForestMutableWorldState.java | 40 +++-- .../worldstate/WorldStateKeyValueStorage.java | 38 +++++ .../worldstate/WorldStateStorage.java | 127 -------------- .../WorldStateStorageCoordinator.java | 155 ++++++++++++++++++ .../core/InMemoryKeyValueStorageProvider.java | 4 +- .../core/InMemoryPrivacyStorageProvider.java | 13 +- .../besu/ethereum/core/TrieGenerator.java | 62 ++++--- .../BlockImportExceptionHandlingTest.java | 14 +- .../proof/WorldStateProofProviderTest.java | 29 ++-- .../WorldStateRangeProofProviderTest.java | 23 ++- .../trie/bonsai/AbstractIsolationTests.java | 12 +- .../bonsai/BonsaiSnapshotIsolationTests.java | 2 +- ...java => BonsaiWorldStateProviderTest.java} | 14 +- .../bonsai/CachedMerkleTrieLoaderTest.java | 5 +- .../ethereum/trie/bonsai/RollingImport.java | 4 +- .../BonsaiWorldStateKeyValueStorageTest.java | 53 +++--- .../worldview/BonsaiWorldStateTest.java | 2 +- .../forest/pruner/MarkSweepPrunerTest.java | 28 ++-- ...tKeyValueStorageWorldStateStorageTest.java | 78 +++++---- .../ForestMutableWorldStateTest.java | 4 +- .../WorldStateDownloaderBenchmark.java | 15 +- .../eth/sync/DefaultSynchronizer.java | 10 +- .../CheckpointDownloaderFactory.java | 12 +- .../checkpointsync/CheckpointSyncActions.java | 8 +- .../CheckpointSyncChainDownloader.java | 6 +- .../eth/sync/fastsync/FastSyncActions.java | 10 +- .../fastsync/FastSyncChainDownloader.java | 6 +- .../eth/sync/fastsync/FastSyncDownloader.java | 23 ++- .../eth/sync/fastsync/SyncTargetManager.java | 10 +- .../AccountTrieNodeDataRequest.java | 36 ++-- .../worldstate/CodeNodeDataRequest.java | 35 +++- .../worldstate/FastDownloaderFactory.java | 37 +++-- .../worldstate/FastWorldDownloadState.java | 21 ++- .../worldstate/FastWorldStateDownloader.java | 16 +- .../worldstate/LoadLocalDataStep.java | 14 +- .../fastsync/worldstate/NodeDataRequest.java | 15 +- .../fastsync/worldstate/PersistDataStep.java | 14 +- .../StorageTrieNodeDataRequest.java | 50 ++++-- .../worldstate/TrieNodeDataRequest.java | 12 +- .../eth/sync/snapsync/LoadLocalDataStep.java | 22 ++- .../eth/sync/snapsync/PersistDataStep.java | 28 ++-- .../eth/sync/snapsync/RequestDataStep.java | 48 ++++-- .../sync/snapsync/SnapDownloaderFactory.java | 10 +- .../eth/sync/snapsync/SnapSyncDownloader.java | 6 +- .../sync/snapsync/SnapWorldDownloadState.java | 35 +++- .../snapsync/SnapWorldStateDownloader.java | 42 +++-- .../request/AccountRangeDataRequest.java | 44 +++-- .../snapsync/request/BytecodeRequest.java | 23 ++- .../snapsync/request/SnapDataRequest.java | 25 +-- .../request/StorageRangeDataRequest.java | 45 +++-- ...ccountFlatDatabaseHealingRangeRequest.java | 11 +- .../heal/AccountTrieNodeHealingRequest.java | 41 +++-- ...torageFlatDatabaseHealingRangeRequest.java | 12 +- .../heal/StorageTrieNodeHealingRequest.java | 41 +++-- .../request/heal/TrieNodeHealingRequest.java | 30 ++-- .../sync/worldstate/WorldDownloadState.java | 8 +- .../CheckPointSyncChainDownloaderTest.java | 34 +++- .../fastsync/FastDownloaderFactoryTest.java | 85 +++++++--- .../sync/fastsync/FastSyncActionsTest.java | 8 +- .../fastsync/FastSyncChainDownloaderTest.java | 10 +- .../sync/fastsync/FastSyncDownloaderTest.java | 150 +++++++++++------ .../FastWorldDownloadStateTest.java | 23 ++- .../FastWorldStateDownloaderTest.java | 111 ++++++++----- .../worldstate/LoadLocalDataStepTest.java | 23 ++- .../worldstate/PersistDataStepTest.java | 24 +-- .../snapsync/AccountHealingTrackingTest.java | 27 +-- .../sync/snapsync/LoadLocalDataStepTest.java | 24 ++- .../sync/snapsync/PersistDataStepTest.java | 28 +++- .../eth/sync/snapsync/RangeManagerTest.java | 19 ++- .../snapsync/SnapWorldDownloadStateTest.java | 43 +++-- .../eth/sync/snapsync/StackTrieTest.java | 35 ++-- .../eth/sync/snapsync/TaskGenerator.java | 31 ++-- ...ntFlatDatabaseHealingRangeRequestTest.java | 59 ++++--- ...geFlatDatabaseHealingRangeRequestTest.java | 38 +++-- .../StorageTrieNodeHealingRequestTest.java | 28 ++-- .../besu/evmtool/BlockchainModule.java | 17 +- .../BonsaiReferenceTestWorldState.java | 15 +- .../ethereum/retesteth/RetestethContext.java | 4 +- .../RangeStorageEntriesCollectorTest.java | 15 +- 105 files changed, 1800 insertions(+), 1244 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java delete mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/{BonsaiWorldStateArchiveTest.java => BonsaiWorldStateProviderTest.java} (98%) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/BackupState.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/BackupState.java index 401b824d5e3..62621328b46 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/BackupState.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/BackupState.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.File; @@ -81,7 +81,7 @@ public void run() { final BesuController besuController = createBesuController(); final MutableBlockchain blockchain = besuController.getProtocolContext().getBlockchain(); - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage forestWorldStateKeyValueStorage = ((ForestWorldStateArchive) besuController.getProtocolContext().getWorldStateArchive()) .getWorldStateStorage(); final EthScheduler scheduler = new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem()); @@ -89,7 +89,11 @@ public void run() { final long targetBlock = Math.min(blockchain.getChainHeadBlockNumber(), this.block); final StateBackupService backup = new StateBackupService( - BesuInfo.version(), blockchain, backupDir.toPath(), scheduler, worldStateStorage); + BesuInfo.version(), + blockchain, + backupDir.toPath(), + scheduler, + forestWorldStateKeyValueStorage); final BackupStatus status = backup.requestBackup(targetBlock, compress, Optional.empty()); final double refValue = Math.pow(2, 256) / 100.0d; diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/RestoreState.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/RestoreState.java index a4b36bd5a6e..8013bb0899f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/RestoreState.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/operator/RestoreState.java @@ -37,8 +37,8 @@ import org.hyperledger.besu.ethereum.trie.PersistVisitor; import org.hyperledger.besu.ethereum.trie.RestoreVisitor; import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.util.io.RollingFileReader; import java.io.IOException; @@ -83,7 +83,7 @@ public class RestoreState implements Runnable { private long trieNodeCount; private boolean compressed; private BesuController besuController; - private WorldStateStorage.Updater updater; + private ForestWorldStateKeyValueStorage.Updater updater; private Path accountFileName(final int fileNumber, final boolean compressed) { return StateBackupService.accountFileName(backupDir, targetBlock, fileNumber, compressed); @@ -249,10 +249,10 @@ private void newWorldStateUpdater() { if (updater != null) { updater.commit(); } - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = ((ForestWorldStateArchive) besuController.getProtocolContext().getWorldStateArchive()) .getWorldStateStorage(); - updater = worldStateStorage.updater(); + updater = worldStateKeyValueStorage.updater(); } private void maybeCommitUpdater() { @@ -263,20 +263,20 @@ private void maybeCommitUpdater() { private void updateCode(final Bytes code) { maybeCommitUpdater(); - updater.putCode(null, code); + updater.putCode(code); } private void updateAccountState(final Bytes32 key, final Bytes value) { maybeCommitUpdater(); // restore by path not supported - updater.putAccountStateTrieNode(null, key, value); + updater.putAccountStateTrieNode(key, value); trieNodeCount++; } private void updateAccountStorage(final Bytes32 key, final Bytes value) { maybeCommitUpdater(); // restore by path not supported - updater.putAccountStorageTrieNode(null, null, key, value); + updater.putAccountStorageTrieNode(key, value); trieNodeCount++; } 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 98dc5549404..4229804903f 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -92,8 +92,9 @@ import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -559,8 +560,8 @@ public BesuController build() { final VariablesStorage variablesStorage = storageProvider.createVariablesStorage(); - final WorldStateStorage worldStateStorage = - storageProvider.createWorldStateStorage(dataStorageConfiguration); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration); final BlockchainStorage blockchainStorage = storageProvider.createBlockchainStorage(protocolSchedule, variablesStorage); @@ -580,7 +581,7 @@ public BesuController build() { .orElseGet(() -> new CachedMerkleTrieLoader(metricsSystem)); final WorldStateArchive worldStateArchive = - createWorldStateArchive(worldStateStorage, blockchain, cachedMerkleTrieLoader); + createWorldStateArchive(worldStateStorageCoordinator, blockchain, cachedMerkleTrieLoader); if (blockchain.getChainHeadBlockNumber() < 1) { genesisState.writeStateTo(worldStateArchive.getMutable()); @@ -707,7 +708,7 @@ public BesuController build() { final Synchronizer synchronizer = createSynchronizer( protocolSchedule, - worldStateStorage, + worldStateStorageCoordinator, protocolContext, maybePruner, ethContext, @@ -739,8 +740,10 @@ public BesuController build() { && DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) { final TrieLogManager trieLogManager = ((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager(); + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = + worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class); final TrieLogPruner trieLogPruner = - createTrieLogPruner(worldStateStorage, blockchain, scheduler); + createTrieLogPruner(worldStateKeyValueStorage, blockchain, scheduler); trieLogManager.subscribe(trieLogPruner); } @@ -773,7 +776,7 @@ public BesuController build() { } private TrieLogPruner createTrieLogPruner( - final WorldStateStorage worldStateStorage, + final WorldStateKeyValueStorage worldStateStorage, final Blockchain blockchain, final EthScheduler scheduler) { final GenesisConfigOptions genesisConfigOptions = configOptionsSupplier.get(); @@ -796,7 +799,7 @@ private TrieLogPruner createTrieLogPruner( * Create synchronizer synchronizer. * * @param protocolSchedule the protocol schedule - * @param worldStateStorage the world state storage + * @param worldStateStorageCoordinator the world state storage * @param protocolContext the protocol context * @param maybePruner the maybe pruner * @param ethContext the eth context @@ -807,7 +810,7 @@ private TrieLogPruner createTrieLogPruner( */ protected Synchronizer createSynchronizer( final ProtocolSchedule protocolSchedule, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolContext protocolContext, final Optional maybePruner, final EthContext ethContext, @@ -819,7 +822,7 @@ protected Synchronizer createSynchronizer( syncConfig, protocolSchedule, protocolContext, - worldStateStorage, + worldStateStorageCoordinator, ethProtocolManager.getBlockBroadcaster(), maybePruner, ethContext, @@ -1042,21 +1045,26 @@ private Optional createSnapProtocolManager( } WorldStateArchive createWorldStateArchive( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final Blockchain blockchain, final CachedMerkleTrieLoader cachedMerkleTrieLoader) { return switch (dataStorageConfiguration.getDataStorageFormat()) { - case BONSAI -> new BonsaiWorldStateProvider( - (BonsaiWorldStateKeyValueStorage) worldStateStorage, - blockchain, - Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()), - cachedMerkleTrieLoader, - besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null), - evmConfiguration); + case BONSAI -> { + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = + worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class); + yield new BonsaiWorldStateProvider( + worldStateKeyValueStorage, + blockchain, + Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()), + cachedMerkleTrieLoader, + besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null), + evmConfiguration); + } case FOREST -> { final WorldStatePreimageStorage preimageStorage = storageProvider.createWorldStatePreimageStorage(); - yield new ForestWorldStateArchive(worldStateStorage, preimageStorage, evmConfiguration); + yield new ForestWorldStateArchive( + worldStateStorageCoordinator, preimageStorage, evmConfiguration); } }; } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index a9de9de7e9f..426c15aed03 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -56,7 +56,7 @@ import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider; @@ -217,7 +217,7 @@ protected PluginServiceFactory createAdditionalPluginServices( @Override protected Synchronizer createSynchronizer( final ProtocolSchedule protocolSchedule, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolContext protocolContext, final Optional maybePruner, final EthContext ethContext, @@ -229,7 +229,7 @@ protected Synchronizer createSynchronizer( (DefaultSynchronizer) super.createSynchronizer( protocolSchedule, - worldStateStorage, + worldStateStorageCoordinator, protocolContext, maybePruner, ethContext, diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index df6a427dc25..b7429ea7b0b 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -47,11 +47,12 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -89,7 +90,6 @@ public class BesuControllerBuilderTest { @Mock Clock clock; @Mock StorageProvider storageProvider; @Mock GasLimitCalculator gasLimitCalculator; - @Mock WorldStateStorage worldStateStorage; @Mock WorldStateArchive worldStateArchive; @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; @Mock WorldStatePreimageStorage worldStatePreimageStorage; @@ -105,6 +105,12 @@ public class BesuControllerBuilderTest { @BeforeEach public void setup() { + + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString()); @@ -132,17 +138,21 @@ public void setup() { lenient() .when( - storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) - .thenReturn(worldStateStorage); + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); lenient() .when(storageProvider.createWorldStatePreimageStorage()) .thenReturn(worldStatePreimageStorage); - lenient().when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); lenient() .when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); - lenient().when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); + besuControllerBuilder = spy(visitWithMockConfigs(new MainnetBesuControllerBuilder())); } @@ -167,18 +177,23 @@ BesuControllerBuilder visitWithMockConfigs(final BesuControllerBuilder builder) @Test public void shouldDisablePruningIfBonsaiIsEnabled() { + DataStorageConfiguration dataStorageConfiguration = + ImmutableDataStorageConfiguration.builder() + .dataStorageFormat(DataStorageFormat.BONSAI) + .bonsaiMaxLayersToLoad(DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD) + .build(); BonsaiWorldState mockWorldState = mock(BonsaiWorldState.class, Answers.RETURNS_DEEP_STUBS); doReturn(worldStateArchive) .when(besuControllerBuilder) .createWorldStateArchive( - any(WorldStateStorage.class), any(Blockchain.class), any(CachedMerkleTrieLoader.class)); + any(WorldStateStorageCoordinator.class), + any(Blockchain.class), + any(CachedMerkleTrieLoader.class)); doReturn(mockWorldState).when(worldStateArchive).getMutable(); + when(storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration)) + .thenReturn(new WorldStateStorageCoordinator(bonsaiWorldStateStorage)); + besuControllerBuilder.isPruningEnabled(true).dataStorageConfiguration(dataStorageConfiguration); - when(storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)) - .thenReturn(bonsaiWorldStateStorage); - besuControllerBuilder - .isPruningEnabled(true) - .dataStorageConfiguration(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); besuControllerBuilder.build(); verify(storageProvider, never()) diff --git a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java index 8489867994c..f10b504010c 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java @@ -52,10 +52,11 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -99,7 +100,6 @@ public class MergeBesuControllerBuilderTest { @Mock Clock clock; @Mock StorageProvider storageProvider; @Mock GasLimitCalculator gasLimitCalculator; - @Mock WorldStateStorage worldStateStorage; @Mock WorldStatePreimageStorage worldStatePreimageStorage; BigInteger networkId = BigInteger.ONE; @@ -113,6 +113,12 @@ public class MergeBesuControllerBuilderTest { @BeforeEach public void setup() { + + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); lenient().when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString()); @@ -146,17 +152,20 @@ public void setup() { lenient() .when( - storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) - .thenReturn(worldStateStorage); + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); lenient() .when(storageProvider.createWorldStatePreimageStorage()) .thenReturn(worldStatePreimageStorage); - lenient().when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); lenient() .when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); - lenient().when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); lenient().when(miningParameters.getTargetGasLimit()).thenReturn(OptionalLong.empty()); besuControllerBuilder = visitWithMockConfigs(new MergeBesuControllerBuilder()); diff --git a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java index 13c712f04ea..e768c49e567 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/QbftBesuControllerBuilderTest.java @@ -48,9 +48,10 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -85,7 +86,6 @@ public class QbftBesuControllerBuilderTest { @Mock private Clock clock; @Mock private StorageProvider storageProvider; @Mock private GasLimitCalculator gasLimitCalculator; - @Mock private WorldStateStorage worldStateStorage; @Mock private WorldStatePreimageStorage worldStatePreimageStorage; private static final BigInteger networkId = BigInteger.ONE; private static final NodeKey nodeKey = NodeKeyUtils.generate(); @@ -98,6 +98,11 @@ public class QbftBesuControllerBuilderTest { @BeforeEach public void setup() { // besu controller setup + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(ForestWorldStateKeyValueStorage.class); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString()); lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString()); when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString()); @@ -113,12 +118,16 @@ public void setup() { new InMemoryKeyValueStorage(), new VariablesKeyValueStorage(new InMemoryKeyValueStorage()), new MainnetBlockHeaderFunctions())); + lenient() .when( - storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) - .thenReturn(worldStateStorage); - lenient().when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); - lenient().when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + storageProvider.createWorldStateStorageCoordinator( + DataStorageConfiguration.DEFAULT_FOREST_CONFIG)) + .thenReturn(worldStateStorageCoordinator); + lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true); + lenient() + .when(worldStateKeyValueStorage.updater()) + .thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class)); lenient() .when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/StateBackupService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/StateBackupService.java index 6ae5125bc5f..50c589c4957 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/StateBackupService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/StateBackupService.java @@ -31,9 +31,9 @@ import org.hyperledger.besu.ethereum.trie.Node; import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator.State; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.util.io.RollingFileWriter; import java.io.IOException; @@ -73,7 +73,7 @@ public class StateBackupService { private final Lock submissionLock = new ReentrantLock(); private final EthScheduler scheduler; private final Blockchain blockchain; - private final WorldStateStorage worldStateStorage; + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage; private final BackupStatus backupStatus = new BackupStatus(); private Path backupDir; @@ -84,12 +84,12 @@ public StateBackupService( final Blockchain blockchain, final Path backupDir, final EthScheduler scheduler, - final WorldStateStorage worldStateStorage) { + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage) { this.besuVersion = besuVersion; this.blockchain = blockchain; this.backupDir = backupDir; this.scheduler = scheduler; - this.worldStateStorage = worldStateStorage; + this.worldStateKeyValueStorage = worldStateKeyValueStorage; } public Path getBackupDir() { @@ -214,7 +214,7 @@ private void backupLeaves() throws IOException { return; } final Optional worldStateRoot = - worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, header.get().getStateRoot()); + worldStateKeyValueStorage.getAccountStateTrieNode(header.get().getStateRoot()); if (worldStateRoot.isEmpty()) { backupStatus.currentAccount = null; return; @@ -226,7 +226,7 @@ private void backupLeaves() throws IOException { final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), header.get().getStateRoot(), Function.identity(), Function.identity()); @@ -246,7 +246,7 @@ private TrieIterator.State visitAccount(final Bytes32 nodeKey, final Node final StateTrieAccountValue account = StateTrieAccountValue.readFrom(new BytesValueRLPInput(nodeValue, false)); - final Bytes code = worldStateStorage.getCode(account.getCodeHash(), null).orElse(Bytes.EMPTY); + final Bytes code = worldStateKeyValueStorage.getCode(account.getCodeHash()).orElse(Bytes.EMPTY); backupStatus.codeSize.addAndGet(code.size()); final BytesValueRLPOutput accountOutput = new BytesValueRLPOutput(); @@ -266,7 +266,7 @@ private TrieIterator.State visitAccount(final Bytes32 nodeKey, final Node // storage is written for each leaf, otherwise the whole trie would have to fit in memory final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), account.getStorageRoot(), Function.identity(), Function.identity()); diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/PrunerIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/PrunerIntegrationTest.java index 77ffc461f86..5b723d80cdb 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/PrunerIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/PrunerIntegrationTest.java @@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -61,11 +61,11 @@ public class PrunerIntegrationTest { private final NoOpMetricsSystem metricsSystem = new NoOpMetricsSystem(); private final Map> hashValueStore = new HashMap<>(); private final InMemoryKeyValueStorage stateStorage = new TestInMemoryStorage(hashValueStore); - private final WorldStateStorage worldStateStorage = + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(stateStorage); private final WorldStateArchive worldStateArchive = new ForestWorldStateArchive( - worldStateStorage, + new WorldStateStorageCoordinator(worldStateKeyValueStorage), new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), EvmConfiguration.DEFAULT); private final InMemoryKeyValueStorage markStorage = new InMemoryKeyValueStorage(); @@ -111,7 +111,7 @@ private void testPruner( final var markSweepPruner = new MarkSweepPruner( - worldStateStorage, blockchain, markStorage, metricsSystem, opsPerTransaction); + worldStateKeyValueStorage, blockchain, markStorage, metricsSystem, opsPerTransaction); final var pruner = new Pruner( markSweepPruner, @@ -243,7 +243,7 @@ private void collectTrieNodes(final MerkleTrie trie, final Set createStateTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), rootHash, Function.identity(), Function.identity()); @@ -251,7 +251,7 @@ private MerkleTrie createStateTrie(final Bytes32 rootHash) { private MerkleTrie createStorageTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.getAccountStorageTrieNode(null, location, hash), + (location, hash) -> worldStateKeyValueStorage.getAccountStorageTrieNode(hash), rootHash, Function.identity(), Function.identity()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java index f5e6f05a05d..349ff8ffbee 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/PrivacyParameters.java @@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.services.PrivacyPluginService; import org.hyperledger.besu.plugin.services.privacy.PrivacyGroupGenesisProvider; @@ -335,8 +335,8 @@ public Builder setPrivacyService(final PrivacyPluginService privacyPluginService public PrivacyParameters build() { final PrivacyParameters config = new PrivacyParameters(); if (enabled) { - final WorldStateStorage privateWorldStateStorage = - storageProvider.createWorldStateStorage(); + final WorldStateStorageCoordinator privateWorldStateStorage = + storageProvider.createWorldStateStorageCoordinator(); final WorldStatePreimageStorage privatePreimageStorage = storageProvider.createWorldStatePreimageStorage(); final WorldStateArchive privateWorldStateArchive = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/PrivacyStorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/PrivacyStorageProvider.java index 2dc167a884b..ea46ffcc6ab 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/PrivacyStorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/PrivacyStorageProvider.java @@ -14,14 +14,17 @@ */ package org.hyperledger.besu.ethereum.privacy.storage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.io.Closeable; public interface PrivacyStorageProvider extends Closeable { - WorldStateStorage createWorldStateStorage(); + WorldStateKeyValueStorage createWorldStateStorage(); + + WorldStateStorageCoordinator createWorldStateStorageCoordinator(); WorldStatePreimageStorage createWorldStatePreimageStorage(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/keyvalue/PrivacyKeyValueStorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/keyvalue/PrivacyKeyValueStorageProvider.java index 1596765bfb1..bb72aeda467 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/keyvalue/PrivacyKeyValueStorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/keyvalue/PrivacyKeyValueStorageProvider.java @@ -21,8 +21,9 @@ import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import java.io.IOException; @@ -47,10 +48,15 @@ public PrivacyKeyValueStorageProvider( } @Override - public WorldStateStorage createWorldStateStorage() { + public WorldStateKeyValueStorage createWorldStateStorage() { return new ForestWorldStateKeyValueStorage(privateWorldStateKeyValueStorage); } + @Override + public WorldStateStorageCoordinator createWorldStateStorageCoordinator() { + return new WorldStateStorageCoordinator(createWorldStateStorage()); + } + @Override public WorldStatePreimageStorage createWorldStatePreimageStorage() { return new WorldStatePreimageKeyValueStorage(privateWorldStatePreimageKeyValueStorage); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java index 16023264b7d..0258ce1034a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProvider.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.SimpleMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.HashMap; import java.util.List; @@ -48,10 +48,10 @@ */ public class WorldStateProofProvider { - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; - public WorldStateProofProvider(final WorldStateStorage worldStateStorage) { - this.worldStateStorage = worldStateStorage; + public WorldStateProofProvider(final WorldStateStorageCoordinator worldStateStorageCoordinator) { + this.worldStateStorageCoordinator = worldStateStorageCoordinator; } public Optional getAccountProof( @@ -59,7 +59,7 @@ public Optional getAccountProof( final Address accountAddress, final List accountStorageKeys) { - if (!worldStateStorage.isWorldStateAvailable(worldStateRoot, null)) { + if (!worldStateStorageCoordinator.isWorldStateAvailable(worldStateRoot, null)) { return Optional.empty(); } else { final Hash accountHash = accountAddress.addressHash(); @@ -122,14 +122,14 @@ public List getStorageProofRelatedNodes( private MerkleTrie newAccountStateTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, rootHash, b -> b, b -> b); + worldStateStorageCoordinator::getAccountStateTrieNode, rootHash, b -> b, b -> b); } private MerkleTrie newAccountStorageTrie( final Hash accountHash, final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateStorageCoordinator.getAccountStorageTrieNode(accountHash, location, hash), rootHash, b -> b, b -> b); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java index 2f3cd3dff47..d927165b1ab 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/StorageProvider.java @@ -18,8 +18,9 @@ import org.hyperledger.besu.ethereum.chain.VariablesStorage; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; @@ -34,7 +35,11 @@ public interface StorageProvider extends Closeable { BlockchainStorage createBlockchainStorage( ProtocolSchedule protocolSchedule, VariablesStorage variablesStorage); - WorldStateStorage createWorldStateStorage(DataStorageConfiguration dataStorageFormat); + WorldStateKeyValueStorage createWorldStateStorage( + DataStorageConfiguration dataStorageConfiguration); + + WorldStateStorageCoordinator createWorldStateStorageCoordinator( + DataStorageConfiguration dataStorageConfiguration); WorldStatePreimageStorage createWorldStatePreimageStorage(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java index 08a1ba23a83..53a3f45469d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java @@ -22,8 +22,9 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; @@ -76,7 +77,7 @@ public BlockchainStorage createBlockchainStorage( } @Override - public WorldStateStorage createWorldStateStorage( + public WorldStateKeyValueStorage createWorldStateStorage( final DataStorageConfiguration dataStorageConfiguration) { if (dataStorageConfiguration.getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { return new BonsaiWorldStateKeyValueStorage(this, metricsSystem, dataStorageConfiguration); @@ -86,6 +87,13 @@ public WorldStateStorage createWorldStateStorage( } } + @Override + public WorldStateStorageCoordinator createWorldStateStorageCoordinator( + final DataStorageConfiguration dataStorageFormatConfiguration) { + return new WorldStateStorageCoordinator( + createWorldStateStorage(dataStorageFormatConfiguration)); + } + @Override public WorldStatePreimageStorage createWorldStatePreimageStorage() { return new WorldStatePreimageKeyValueStorage(worldStatePreimageStorage); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProvider.java index ad223b407dd..0230a2258bc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProvider.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.plugin.BesuContext; @@ -63,26 +64,30 @@ public class BonsaiWorldStateProvider implements WorldStateArchive { private final CachedWorldStorageManager cachedWorldStorageManager; private final TrieLogManager trieLogManager; private final BonsaiWorldState persistedState; - private final BonsaiWorldStateKeyValueStorage worldStateStorage; + private final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage; private final CachedMerkleTrieLoader cachedMerkleTrieLoader; public BonsaiWorldStateProvider( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Blockchain blockchain, final Optional maxLayersToLoad, final CachedMerkleTrieLoader cachedMerkleTrieLoader, final BesuContext pluginContext, final EvmConfiguration evmConfiguration) { - this.cachedWorldStorageManager = new CachedWorldStorageManager(this, worldStateStorage); + this.worldStateKeyValueStorage = worldStateKeyValueStorage; + this.cachedWorldStorageManager = new CachedWorldStorageManager(this, worldStateKeyValueStorage); + // TODO: de-dup constructors this.trieLogManager = new TrieLogManager( - blockchain, worldStateStorage, maxLayersToLoad.orElse(RETAINED_LAYERS), pluginContext); + blockchain, + worldStateKeyValueStorage, + maxLayersToLoad.orElse(RETAINED_LAYERS), + pluginContext); this.blockchain = blockchain; - this.worldStateStorage = worldStateStorage; this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; - this.persistedState = new BonsaiWorldState(this, worldStateStorage, evmConfiguration); + this.persistedState = new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration); blockchain .getBlockHeader(persistedState.getWorldStateBlockHash()) .ifPresent( @@ -95,15 +100,15 @@ public BonsaiWorldStateProvider( BonsaiWorldStateProvider( final CachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager, - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Blockchain blockchain, final CachedMerkleTrieLoader cachedMerkleTrieLoader, final EvmConfiguration evmConfiguration) { this.cachedWorldStorageManager = cachedWorldStorageManager; this.trieLogManager = trieLogManager; this.blockchain = blockchain; - this.worldStateStorage = worldStateStorage; - this.persistedState = new BonsaiWorldState(this, worldStateStorage, evmConfiguration); + this.worldStateKeyValueStorage = worldStateKeyValueStorage; + this.persistedState = new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration); this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; blockchain .getBlockHeader(persistedState.getWorldStateBlockHash()) @@ -132,7 +137,7 @@ public Optional get(final Hash rootHash, final Hash blockHash) { public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { return cachedWorldStorageManager.containWorldStateStorage(blockHash) || persistedState.blockHash().equals(blockHash) - || worldStateStorage.isWorldStateAvailable(rootHash, blockHash); + || worldStateKeyValueStorage.isWorldStateAvailable(rootHash, blockHash); } @Override @@ -281,12 +286,12 @@ public MutableWorldState getMutable() { */ public void prepareStateHealing(final Address address, final Bytes location) { final Set keysToDelete = new HashSet<>(); - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = worldStateStorage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = worldStateKeyValueStorage.updater(); final Hash accountHash = address.addressHash(); final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( (l, h) -> { - final Optional node = worldStateStorage.getAccountStateTrieNode(l, h); + final Optional node = worldStateKeyValueStorage.getAccountStateTrieNode(l, h); if (node.isPresent()) { keysToDelete.add(l); } @@ -306,7 +311,8 @@ public void prepareStateHealing(final Address address, final Bytes location) { new StoredMerklePatriciaTrie<>( (l, h) -> { Optional node = - worldStateStorage.getAccountStorageTrieNode(accountHash, l, h); + worldStateKeyValueStorage.getAccountStorageTrieNode( + accountHash, l, h); if (node.isPresent()) { keysToDelete.add(Bytes.concatenate(accountHash, l)); } @@ -326,10 +332,10 @@ public void prepareStateHealing(final Address address, final Bytes location) { LOG.warn("Invalid node for account {} at location {}", address, location); // ignore } - keysToDelete.forEach(bytes -> updater.removeAccountStateTrieNode(bytes, null)); + keysToDelete.forEach(bytes -> updater.removeAccountStateTrieNode(bytes)); updater.commit(); - worldStateStorage.downgradeToPartialFlatDbMode(); + worldStateKeyValueStorage.downgradeToPartialFlatDbMode(); } public TrieLogManager getTrieLogManager() { @@ -357,7 +363,8 @@ public Optional getAccountProof( try (BonsaiWorldState ws = (BonsaiWorldState) getMutable(blockHeader, false).orElse(null)) { if (ws != null) { final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(ws.getWorldStateStorage()); + new WorldStateProofProvider( + new WorldStateStorageCoordinator(ws.getWorldStateStorage())); return mapper.apply( worldStateProofProvider.getAccountProof( ws.getWorldStateRootHash(), accountAddress, accountStorageKeys)); @@ -376,7 +383,7 @@ public Optional getNodeData(final Hash hash) { @Override public void close() { try { - worldStateStorage.close(); + worldStateKeyValueStorage.close(); } catch (Exception e) { // no op } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedBonsaiWorldView.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedBonsaiWorldView.java index 6cdfd10cf9c..2b8fd69d114 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedBonsaiWorldView.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedBonsaiWorldView.java @@ -24,7 +24,7 @@ public class CachedBonsaiWorldView implements BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber { - private BonsaiWorldStateKeyValueStorage worldStateStorage; + private BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage; private final BlockHeader blockHeader; private long worldViewSubscriberId; private static final Logger LOG = LoggerFactory.getLogger(CachedBonsaiWorldView.class); @@ -32,12 +32,12 @@ public class CachedBonsaiWorldView public CachedBonsaiWorldView( final BlockHeader blockHeader, final BonsaiWorldStateKeyValueStorage worldView) { this.blockHeader = blockHeader; - this.worldStateStorage = worldView; - this.worldViewSubscriberId = worldStateStorage.subscribe(this); + this.worldStateKeyValueStorage = worldView; + this.worldViewSubscriberId = worldStateKeyValueStorage.subscribe(this); } public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { - return worldStateStorage; + return worldStateKeyValueStorage; } public long getBlockNumber() { @@ -49,9 +49,9 @@ public Hash getBlockHash() { } public synchronized void close() { - worldStateStorage.unSubscribe(this.worldViewSubscriberId); + worldStateKeyValueStorage.unSubscribe(this.worldViewSubscriberId); try { - worldStateStorage.close(); + worldStateKeyValueStorage.close(); } catch (final Exception e) { LOG.warn("Failed to close worldstate storage for block " + blockHeader.toLogString(), e); } @@ -60,9 +60,9 @@ public synchronized void close() { public synchronized void updateWorldStateStorage( final BonsaiWorldStateKeyValueStorage newWorldStateStorage) { long newSubscriberId = newWorldStateStorage.subscribe(this); - this.worldStateStorage.unSubscribe(this.worldViewSubscriberId); - BonsaiWorldStateKeyValueStorage oldWorldStateStorage = this.worldStateStorage; - this.worldStateStorage = newWorldStateStorage; + this.worldStateKeyValueStorage.unSubscribe(this.worldViewSubscriberId); + BonsaiWorldStateKeyValueStorage oldWorldStateStorage = this.worldStateKeyValueStorage; + this.worldStateKeyValueStorage = newWorldStateStorage; this.worldViewSubscriberId = newSubscriberId; try { oldWorldStateStorage.close(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedMerkleTrieLoader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedMerkleTrieLoader.java index 832ca6f7dbd..cbd1fc820d8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedMerkleTrieLoader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedMerkleTrieLoader.java @@ -57,24 +57,25 @@ public CachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) { } public void preLoadAccount( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Hash worldStateRootHash, final Address account) { CompletableFuture.runAsync( - () -> cacheAccountNodes(worldStateStorage, worldStateRootHash, account)); + () -> cacheAccountNodes(worldStateKeyValueStorage, worldStateRootHash, account)); } @VisibleForTesting public void cacheAccountNodes( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Hash worldStateRootHash, final Address account) { - final long storageSubscriberId = worldStateStorage.subscribe(this); + final long storageSubscriberId = worldStateKeyValueStorage.subscribe(this); try { final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> { - Optional node = getAccountStateTrieNode(worldStateStorage, location, hash); + Optional node = + getAccountStateTrieNode(worldStateKeyValueStorage, location, hash); node.ifPresent(bytes -> accountNodes.put(Hash.hash(bytes), bytes)); return node; }, @@ -85,26 +86,27 @@ public void cacheAccountNodes( } catch (MerkleTrieException e) { // ignore exception for the cache } finally { - worldStateStorage.unSubscribe(storageSubscriberId); + worldStateKeyValueStorage.unSubscribe(storageSubscriberId); } } public void preLoadStorageSlot( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Address account, final StorageSlotKey slotKey) { - CompletableFuture.runAsync(() -> cacheStorageNodes(worldStateStorage, account, slotKey)); + CompletableFuture.runAsync( + () -> cacheStorageNodes(worldStateKeyValueStorage, account, slotKey)); } @VisibleForTesting public void cacheStorageNodes( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Address account, final StorageSlotKey slotKey) { final Hash accountHash = account.addressHash(); - final long storageSubscriberId = worldStateStorage.subscribe(this); + final long storageSubscriberId = worldStateKeyValueStorage.subscribe(this); try { - worldStateStorage + worldStateKeyValueStorage .getStateTrieNode(Bytes.concatenate(accountHash, Bytes.EMPTY)) .ifPresent( storageRoot -> { @@ -114,7 +116,7 @@ public void cacheStorageNodes( (location, hash) -> { Optional node = getAccountStorageTrieNode( - worldStateStorage, accountHash, location, hash); + worldStateKeyValueStorage, accountHash, location, hash); node.ifPresent(bytes -> storageNodes.put(Hash.hash(bytes), bytes)); return node; }, @@ -127,7 +129,7 @@ public void cacheStorageNodes( } }); } finally { - worldStateStorage.unSubscribe(storageSubscriberId); + worldStateKeyValueStorage.unSubscribe(storageSubscriberId); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedWorldStorageManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedWorldStorageManager.java index 6ca38a27a92..3944b72a732 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedWorldStorageManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/cache/CachedWorldStorageManager.java @@ -47,11 +47,11 @@ public class CachedWorldStorageManager private CachedWorldStorageManager( final BonsaiWorldStateProvider archive, - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Map cachedWorldStatesByHash, final EvmConfiguration evmConfiguration) { - worldStateStorage.subscribe(this); - this.rootWorldStateStorage = worldStateStorage; + worldStateKeyValueStorage.subscribe(this); + this.rootWorldStateStorage = worldStateKeyValueStorage; this.cachedWorldStatesByHash = cachedWorldStatesByHash; this.archive = archive; this.evmConfiguration = evmConfiguration; @@ -59,8 +59,8 @@ private CachedWorldStorageManager( public CachedWorldStorageManager( final BonsaiWorldStateProvider archive, - final BonsaiWorldStateKeyValueStorage worldStateStorage) { - this(archive, worldStateStorage, new ConcurrentHashMap<>(), EvmConfiguration.DEFAULT); + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage) { + this(archive, worldStateKeyValueStorage, new ConcurrentHashMap<>(), EvmConfiguration.DEFAULT); } public synchronized void addCachedLayer( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java index c357f1d56c2..e20d844738e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java @@ -50,11 +50,12 @@ public BonsaiSnapshotWorldStateKeyValueStorage( } public BonsaiSnapshotWorldStateKeyValueStorage( - final BonsaiWorldStateKeyValueStorage worldStateStorage) { + final BonsaiWorldStateKeyValueStorage worldStateStorageKeyValueStorage) { this( - worldStateStorage, - ((SnappableKeyValueStorage) worldStateStorage.composedWorldStateStorage).takeSnapshot(), - worldStateStorage.trieLogStorage); + worldStateStorageKeyValueStorage, + ((SnappableKeyValueStorage) worldStateStorageKeyValueStorage.composedWorldStateStorage) + .takeSnapshot(), + worldStateStorageKeyValueStorage.trieLogStorage); } private boolean isClosedGet() { @@ -66,7 +67,7 @@ private boolean isClosedGet() { } @Override - public BonsaiUpdater updater() { + public Updater updater() { return new Updater( ((SnappedKeyValueStorage) composedWorldStateStorage).getSnapshotTransaction(), trieLogStorage.startTransaction(), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java index 4a4dcf44e1a..5f477afebaf 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorage.java @@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -45,7 +45,6 @@ import java.util.NavigableMap; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -54,8 +53,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@SuppressWarnings("unused") -public class BonsaiWorldStateKeyValueStorage implements WorldStateStorage, AutoCloseable { +public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorage, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class); // 0x776f726c64526f6f74 @@ -104,12 +102,10 @@ public DataStorageFormat getDataStorageFormat() { return DataStorageFormat.BONSAI; } - @Override public FlatDbMode getFlatDbMode() { return flatDbStrategyProvider.getFlatDbMode(); } - @Override public Optional getCode(final Hash codeHash, final Hash accountHash) { if (codeHash.equals(Hash.EMPTY)) { return Optional.of(Bytes.EMPTY); @@ -130,7 +126,6 @@ public Optional getAccount(final Hash accountHash) { composedWorldStateStorage); } - @Override public Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); @@ -142,7 +137,6 @@ public Optional getAccountStateTrieNode(final Bytes location, final Bytes } } - @Override public Optional getAccountStorageTrieNode( final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { @@ -155,7 +149,6 @@ public Optional getAccountStorageTrieNode( } } - @Override public Optional getTrieNodeUnsafe(final Bytes key) { return composedWorldStateStorage .get(TRIE_BRANCH_STORAGE, Bytes.concatenate(key).toArrayUnsafe()) @@ -216,7 +209,6 @@ public Optional getStorageValueByStorageSlotKey( composedWorldStateStorage); } - @Override public Map streamFlatAccounts( final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return flatDbStrategyProvider @@ -224,7 +216,6 @@ public Map streamFlatAccounts( .streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max); } - @Override public Map streamFlatStorages( final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { return flatDbStrategyProvider @@ -238,12 +229,6 @@ public NavigableMap storageEntriesFrom( throw new RuntimeException("Bonsai Tries does not currently support enumerating storage"); } - @Override - public Optional getNodeData(final Bytes location, final Bytes32 hash) { - return Optional.empty(); - } - - @Override public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) { return composedWorldStateStorage .get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY) @@ -272,13 +257,11 @@ public void clear() { composedWorldStateStorage); // force reload of flat db reader strategy } - @Override public void clearTrieLog() { subscribers.forEach(BonsaiStorageSubscriber::onClearTrieLog); trieLogStorage.clear(); } - @Override public void clearFlatDatabase() { subscribers.forEach(BonsaiStorageSubscriber::onClearFlatDatabaseStorage); flatDbStrategyProvider @@ -287,18 +270,13 @@ public void clearFlatDatabase() { } @Override - public BonsaiUpdater updater() { + public Updater updater() { return new Updater( composedWorldStateStorage.startTransaction(), trieLogStorage.startTransaction(), flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage)); } - @Override - public long prune(final Predicate inUseCheck) { - throw new RuntimeException("Bonsai Tries do not work with pruning."); - } - public boolean pruneTrieLog(final Hash blockHash) { try { return trieLogStorage.tryDelete(blockHash.toArrayUnsafe()); @@ -308,38 +286,11 @@ public boolean pruneTrieLog(final Hash blockHash) { } } - @Override - public long addNodeAddedListener(final NodesAddedListener listener) { - throw new RuntimeException("addNodeAddedListener not available"); - } - - @Override - public void removeNodeAddedListener(final long id) { - throw new RuntimeException("removeNodeAddedListener not available"); - } - public FlatDbStrategy getFlatDbStrategy() { return flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage); } - public interface BonsaiUpdater extends WorldStateStorage.Updater { - BonsaiUpdater removeCode(final Hash accountHash, final Hash codeHash); - - BonsaiUpdater removeAccountInfoState(final Hash accountHash); - - BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes accountValue); - - BonsaiUpdater putStorageValueBySlotHash( - final Hash accountHash, final Hash slotHash, final Bytes storage); - - void removeStorageValueBySlotHash(final Hash accountHash, final Hash slotHash); - - SegmentedKeyValueStorageTransaction getWorldStateTransaction(); - - KeyValueStorageTransaction getTrieLogStorageTransaction(); - } - - public static class Updater implements BonsaiUpdater { + public static class Updater implements WorldStateKeyValueStorage.Updater { private final SegmentedKeyValueStorageTransaction composedWorldStateTransaction; private final KeyValueStorageTransaction trieLogStorageTransaction; @@ -355,14 +306,18 @@ public Updater( this.flatDbStrategy = flatDbStrategy; } - @Override - public BonsaiUpdater removeCode(final Hash accountHash, final Hash codeHash) { + public Updater removeCode(final Hash accountHash, final Hash codeHash) { flatDbStrategy.removeFlatCode(composedWorldStateTransaction, accountHash, codeHash); return this; } - @Override - public BonsaiUpdater putCode(final Hash accountHash, final Hash codeHash, final Bytes code) { + public Updater putCode(final Hash accountHash, final Bytes code) { + // Skip the hash calculation for empty code + final Hash codeHash = code.size() == 0 ? Hash.EMPTY : Hash.hash(code); + return putCode(accountHash, codeHash, code); + } + + public Updater putCode(final Hash accountHash, final Hash codeHash, final Bytes code) { if (code.isEmpty()) { // Don't save empty values return this; @@ -371,14 +326,12 @@ public BonsaiUpdater putCode(final Hash accountHash, final Hash codeHash, final return this; } - @Override - public BonsaiUpdater removeAccountInfoState(final Hash accountHash) { + public Updater removeAccountInfoState(final Hash accountHash) { flatDbStrategy.removeFlatAccount(composedWorldStateTransaction, accountHash); return this; } - @Override - public BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes accountValue) { + public Updater putAccountInfoState(final Hash accountHash, final Bytes accountValue) { if (accountValue.isEmpty()) { // Don't save empty values return this; @@ -387,9 +340,7 @@ public BonsaiUpdater putAccountInfoState(final Hash accountHash, final Bytes acc return this; } - @Override - public WorldStateStorage.Updater saveWorldState( - final Bytes blockHash, final Bytes32 nodeHash, final Bytes node) { + public Updater saveWorldState(final Bytes blockHash, final Bytes32 nodeHash, final Bytes node) { composedWorldStateTransaction.put( TRIE_BRANCH_STORAGE, Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe()); composedWorldStateTransaction.put( @@ -399,8 +350,7 @@ public WorldStateStorage.Updater saveWorldState( return this; } - @Override - public BonsaiUpdater putAccountStateTrieNode( + public Updater putAccountStateTrieNode( final Bytes location, final Bytes32 nodeHash, final Bytes node) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { // Don't save empty nodes @@ -411,14 +361,12 @@ public BonsaiUpdater putAccountStateTrieNode( return this; } - @Override - public BonsaiUpdater removeAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { + public Updater removeAccountStateTrieNode(final Bytes location) { composedWorldStateTransaction.remove(TRIE_BRANCH_STORAGE, location.toArrayUnsafe()); return this; } - @Override - public synchronized BonsaiUpdater putAccountStorageTrieNode( + public synchronized Updater putAccountStorageTrieNode( final Hash accountHash, final Bytes location, final Bytes32 nodeHash, final Bytes node) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { // Don't save empty nodes @@ -431,27 +379,23 @@ public synchronized BonsaiUpdater putAccountStorageTrieNode( return this; } - @Override - public synchronized BonsaiUpdater putStorageValueBySlotHash( + public synchronized Updater putStorageValueBySlotHash( final Hash accountHash, final Hash slotHash, final Bytes storage) { flatDbStrategy.putFlatAccountStorageValueByStorageSlotHash( composedWorldStateTransaction, accountHash, slotHash, storage); return this; } - @Override public synchronized void removeStorageValueBySlotHash( final Hash accountHash, final Hash slotHash) { flatDbStrategy.removeFlatAccountStorageValueByStorageSlotHash( composedWorldStateTransaction, accountHash, slotHash); } - @Override public SegmentedKeyValueStorageTransaction getWorldStateTransaction() { return composedWorldStateTransaction; } - @Override public KeyValueStorageTransaction getTrieLogStorageTransaction() { return trieLogStorageTransaction; } @@ -463,7 +407,6 @@ public void commit() { composedWorldStateTransaction.commit(); } - @Override public void rollback() { composedWorldStateTransaction.rollback(); trieLogStorageTransaction.rollback(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogManager.java index 5102b7a0b90..19ac6285f5c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/trielog/TrieLogManager.java @@ -50,11 +50,11 @@ public class TrieLogManager { public TrieLogManager( final Blockchain blockchain, - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final long maxLayersToLoad, final BesuContext pluginContext) { this.blockchain = blockchain; - this.rootWorldStateStorage = worldStateStorage; + this.rootWorldStateStorage = worldStateKeyValueStorage; this.maxLayersToLoad = maxLayersToLoad; this.trieLogFactory = setupTrieLogFactory(pluginContext); } @@ -68,7 +68,7 @@ public synchronized void saveTrieLog( // if it's only in memory we need to save it // for example, in case of reorg we don't replace a trielog layer if (rootWorldStateStorage.getTrieLog(forBlockHeader.getHash()).isEmpty()) { - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater stateUpdater = + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater = forWorldState.getWorldStateStorage().updater(); boolean success = false; try { @@ -104,7 +104,7 @@ private void persistTrieLog( final BlockHeader blockHeader, final Hash worldStateRootHash, final TrieLog trieLog, - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater stateUpdater) { + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) { LOG.atDebug() .setMessage("Persisting trie log for block hash {} and world state root {}") .addArgument(blockHeader::toLogString) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldState.java index 93c0ab30902..9e5472f5706 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldState.java @@ -41,7 +41,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator.StorageConsumingMap; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -71,7 +71,7 @@ public class BonsaiWorldState private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class); - protected BonsaiWorldStateKeyValueStorage worldStateStorage; + protected BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage; protected final CachedMerkleTrieLoader cachedMerkleTrieLoader; protected final CachedWorldStorageManager cachedWorldStorageManager; @@ -84,10 +84,10 @@ public class BonsaiWorldState public BonsaiWorldState( final BonsaiWorldStateProvider archive, - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final EvmConfiguration evmConfiguration) { this( - worldStateStorage, + worldStateKeyValueStorage, archive.getCachedMerkleTrieLoader(), archive.getCachedWorldStorageManager(), archive.getTrieLogManager(), @@ -95,17 +95,19 @@ public BonsaiWorldState( } public BonsaiWorldState( - final BonsaiWorldStateKeyValueStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final CachedMerkleTrieLoader cachedMerkleTrieLoader, final CachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager, final EvmConfiguration evmConfiguration) { - this.worldStateStorage = worldStateStorage; + this.worldStateKeyValueStorage = worldStateKeyValueStorage; this.worldStateRootHash = Hash.wrap( - Bytes32.wrap(worldStateStorage.getWorldStateRootHash().orElse(Hash.EMPTY_TRIE_HASH))); + Bytes32.wrap( + worldStateKeyValueStorage.getWorldStateRootHash().orElse(getEmptyTrieHash()))); this.worldStateBlockHash = - Hash.wrap(Bytes32.wrap(worldStateStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); + Hash.wrap( + Bytes32.wrap(worldStateKeyValueStorage.getWorldStateBlockHash().orElse(Hash.ZERO))); this.accumulator = new BonsaiWorldStateUpdateAccumulator( this, @@ -150,16 +152,16 @@ public Hash getWorldStateRootHash() { @Override public boolean isPersisted() { - return isPersisted(worldStateStorage); + return isPersisted(worldStateKeyValueStorage); } - private boolean isPersisted(final WorldStateStorage worldStateStorage) { - return !(worldStateStorage instanceof BonsaiSnapshotWorldStateKeyValueStorage); + private boolean isPersisted(final WorldStateKeyValueStorage worldStateKeyValueStorage) { + return !(worldStateKeyValueStorage instanceof BonsaiSnapshotWorldStateKeyValueStorage); } @Override public Optional getCode(@Nonnull final Address address, final Hash codeHash) { - return worldStateStorage.getCode(codeHash, address.addressHash()); + return worldStateKeyValueStorage.getCode(codeHash, address.addressHash()); } /** @@ -174,11 +176,11 @@ public void resetWorldStateTo(final BlockHeader blockHeader) { @Override public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { - return worldStateStorage; + return worldStateKeyValueStorage; } private Hash calculateRootHash( - final Optional maybeStateUpdater, + final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { clearStorage(maybeStateUpdater, worldStateUpdater); @@ -203,7 +205,8 @@ private Hash calculateRootHash( final StoredMerklePatriciaTrie accountTrie = createTrie( (location, hash) -> - cachedMerkleTrieLoader.getAccountStateTrieNode(worldStateStorage, location, hash), + cachedMerkleTrieLoader.getAccountStateTrieNode( + worldStateKeyValueStorage, location, hash), worldStateRootHash); // for manicured tries and composting, collect branches here (not implemented) @@ -225,7 +228,7 @@ private Hash calculateRootHash( } private void updateTheAccounts( - final Optional maybeStateUpdater, + final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater, final StoredMerklePatriciaTrie accountTrie) { for (final Map.Entry> accountUpdate : @@ -257,7 +260,7 @@ private void updateTheAccounts( @VisibleForTesting protected void updateCode( - final Optional maybeStateUpdater, + final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { maybeStateUpdater.ifPresent( bonsaiUpdater -> { @@ -289,7 +292,7 @@ private boolean codeIsEmpty(final Bytes value) { } private void updateAccountStorageState( - final Optional maybeStateUpdater, + final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater, final Map.Entry>> storageAccountUpdate) { @@ -308,7 +311,7 @@ private void updateAccountStorageState( createTrie( (location, key) -> cachedMerkleTrieLoader.getAccountStorageTrieNode( - worldStateStorage, updatedAddressHash, location, key), + worldStateKeyValueStorage, updatedAddressHash, location, key), storageRoot); // for manicured tries and composting, collect branches here (not implemented) @@ -355,13 +358,13 @@ private void updateAccountStorageState( } private void clearStorage( - final Optional maybeStateUpdater, + final Optional maybeStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { for (final Address address : worldStateUpdater.getStorageToClear()) { // because we are clearing persisted values we need the account root as persisted final BonsaiAccount oldAccount = - worldStateStorage + worldStateKeyValueStorage .getAccount(address.addressHash()) .map(bytes -> BonsaiAccount.fromRLP(BonsaiWorldState.this, address, bytes, true)) .orElse(null); @@ -421,7 +424,8 @@ public void persist(final BlockHeader blockHeader) { boolean success = false; - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater stateUpdater = worldStateStorage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater = + worldStateKeyValueStorage.updater(); Runnable saveTrieLog = () -> {}; try { @@ -545,7 +549,7 @@ public Hash frontierRootHash() { return calculateRootHash( Optional.of( new BonsaiWorldStateKeyValueStorage.Updater( - noOpSegmentedTx, noOpTx, worldStateStorage.getFlatDbStrategy())), + noOpSegmentedTx, noOpTx, worldStateKeyValueStorage.getFlatDbStrategy())), accumulator.copy()); } @@ -560,14 +564,14 @@ public Stream streamAccounts(final Bytes32 startKeyHash, fina @Override public Account get(final Address address) { - return worldStateStorage + return worldStateKeyValueStorage .getAccount(address.addressHash()) .map(bytes -> BonsaiAccount.fromRLP(accumulator, address, bytes, true)) .orElse(null); } protected Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { - return worldStateStorage.getAccountStateTrieNode(location, nodeHash); + return worldStateKeyValueStorage.getAccountStateTrieNode(location, nodeHash); } private void writeTrieNode( @@ -580,11 +584,11 @@ private void writeTrieNode( protected Optional getStorageTrieNode( final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { - return worldStateStorage.getAccountStorageTrieNode(accountHash, location, nodeHash); + return worldStateKeyValueStorage.getAccountStorageTrieNode(accountHash, location, nodeHash); } private void writeStorageTrieNode( - final WorldStateStorage.Updater stateUpdater, + final BonsaiWorldStateKeyValueStorage.Updater stateUpdater, final Hash accountHash, final Bytes location, final Bytes32 nodeHash, @@ -601,7 +605,7 @@ public UInt256 getStorageValue(final Address address, final UInt256 storageKey) @Override public Optional getStorageValueByStorageSlotKey( final Address address, final StorageSlotKey storageSlotKey) { - return worldStateStorage + return worldStateKeyValueStorage .getStorageValueByStorageSlotKey(address.addressHash(), storageSlotKey) .map(UInt256::fromBytes); } @@ -610,7 +614,7 @@ public Optional getStorageValueByStorageSlotKey( final Supplier> storageRootSupplier, final Address address, final StorageSlotKey storageSlotKey) { - return worldStateStorage + return worldStateKeyValueStorage .getStorageValueByStorageSlotKey(storageRootSupplier, address.addressHash(), storageSlotKey) .map(UInt256::fromBytes); } @@ -631,7 +635,7 @@ public Map getAllAccountStorage(final Address address, final Has @Override public MutableWorldState freeze() { this.isFrozen = true; - this.worldStateStorage = new BonsaiWorldStateLayerStorage(worldStateStorage); + this.worldStateKeyValueStorage = new BonsaiWorldStateLayerStorage(worldStateKeyValueStorage); return this; } @@ -645,7 +649,7 @@ private StoredMerklePatriciaTrie createTrie( public void close() { try { if (!isPersisted()) { - this.worldStateStorage.close(); + this.worldStateKeyValueStorage.close(); if (isFrozen) { closeFrozenStorage(); } @@ -658,7 +662,7 @@ public void close() { private void closeFrozenStorage() { try { final BonsaiWorldStateLayerStorage worldStateLayerStorage = - (BonsaiWorldStateLayerStorage) worldStateStorage; + (BonsaiWorldStateLayerStorage) worldStateKeyValueStorage; if (!isPersisted(worldStateLayerStorage.getParentWorldStateStorage())) { worldStateLayerStorage.getParentWorldStateStorage().close(); } @@ -671,4 +675,8 @@ protected Hash hashAndSavePreImage(final Bytes value) { // by default do not save has preImages return Hash.hash(value); } + + protected Hash getEmptyTrieHash() { + return Hash.EMPTY_TRIE_HASH; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/ForestWorldStateArchive.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/ForestWorldStateArchive.java index b04c22a5543..d38976b644b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/ForestWorldStateArchive.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/ForestWorldStateArchive.java @@ -22,10 +22,11 @@ import org.hyperledger.besu.ethereum.proof.WorldStateProof; import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldState; @@ -37,7 +38,7 @@ import org.apache.tuweni.units.bigints.UInt256; public class ForestWorldStateArchive implements WorldStateArchive { - private final WorldStateStorage worldStateStorage; + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage; private final WorldStatePreimageStorage preimageStorage; private final WorldStateProofProvider worldStateProof; private final EvmConfiguration evmConfiguration; @@ -45,12 +46,13 @@ public class ForestWorldStateArchive implements WorldStateArchive { private static final Hash EMPTY_ROOT_HASH = Hash.wrap(MerkleTrie.EMPTY_TRIE_NODE_HASH); public ForestWorldStateArchive( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStatePreimageStorage preimageStorage, final EvmConfiguration evmConfiguration) { - this.worldStateStorage = worldStateStorage; + this.worldStateKeyValueStorage = + worldStateStorageCoordinator.getStrategy(ForestWorldStateKeyValueStorage.class); this.preimageStorage = preimageStorage; - this.worldStateProof = new WorldStateProofProvider(worldStateStorage); + this.worldStateProof = new WorldStateProofProvider(worldStateStorageCoordinator); this.evmConfiguration = evmConfiguration; } @@ -61,7 +63,7 @@ public Optional get(final Hash rootHash, final Hash blockHash) { @Override public boolean isWorldStateAvailable(final Hash rootHash, final Hash blockHash) { - return worldStateStorage.isWorldStateAvailable(rootHash, blockHash); + return worldStateKeyValueStorage.isWorldStateAvailable(rootHash); } @Override @@ -72,12 +74,12 @@ public Optional getMutable( @Override public Optional getMutable(final Hash rootHash, final Hash blockHash) { - if (!worldStateStorage.isWorldStateAvailable(rootHash, blockHash)) { + if (!worldStateKeyValueStorage.isWorldStateAvailable(rootHash)) { return Optional.empty(); } return Optional.of( new ForestMutableWorldState( - rootHash, worldStateStorage, preimageStorage, evmConfiguration)); + rootHash, worldStateKeyValueStorage, preimageStorage, evmConfiguration)); } @Override @@ -93,11 +95,11 @@ public void resetArchiveStateTo(final BlockHeader blockHeader) { @Override public Optional getNodeData(final Hash hash) { // query by location is not supported, only query by content - return worldStateStorage.getNodeData(null, hash); + return worldStateKeyValueStorage.getNodeData(hash); } - public WorldStateStorage getWorldStateStorage() { - return worldStateStorage; + public ForestWorldStateKeyValueStorage getWorldStateStorage() { + return worldStateKeyValueStorage; } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPruner.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPruner.java index 0559400a874..45b4b2ee3a0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPruner.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPruner.java @@ -19,9 +19,9 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; @@ -58,7 +58,7 @@ public class MarkSweepPruner { private static final int MAX_MARKING_THREAD_POOL_SIZE = 2; private final int operationsPerTransaction; - private final WorldStateStorage worldStateStorage; + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage; private final MutableBlockchain blockchain; private final KeyValueStorage markStorage; private final Counter markedNodesCounter; @@ -71,20 +71,25 @@ public class MarkSweepPruner { private final Set pendingMarks = Collections.newSetFromMap(new ConcurrentHashMap<>()); public MarkSweepPruner( - final WorldStateStorage worldStateStorage, + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage, final MutableBlockchain blockchain, final KeyValueStorage markStorage, final ObservableMetricsSystem metricsSystem) { - this(worldStateStorage, blockchain, markStorage, metricsSystem, DEFAULT_OPS_PER_TRANSACTION); + this( + worldStateKeyValueStorage, + blockchain, + markStorage, + metricsSystem, + DEFAULT_OPS_PER_TRANSACTION); } public MarkSweepPruner( - final WorldStateStorage worldStateStorage, + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage, final MutableBlockchain blockchain, final KeyValueStorage markStorage, final ObservableMetricsSystem metricsSystem, final int operationsPerTransaction) { - this.worldStateStorage = worldStateStorage; + this.worldStateKeyValueStorage = worldStateKeyValueStorage; this.markStorage = markStorage; this.blockchain = blockchain; this.operationsPerTransaction = operationsPerTransaction; @@ -125,7 +130,7 @@ public void prepare() { // last time, causing the first sweep to be smaller than it needs to be. clearMarks(); - nodeAddedListenerId = worldStateStorage.addNodeAddedListener(this::markNodes); + nodeAddedListenerId = worldStateKeyValueStorage.addNodeAddedListener(this::markNodes); } /** @@ -196,34 +201,34 @@ public void sweepBefore(final long markedBlockNumber) { // Sweep state roots first, walking backwards until we get to a state root that isn't in the // storage long prunedNodeCount = 0; - WorldStateStorage.Updater updater = worldStateStorage.updater(); + ForestWorldStateKeyValueStorage.Updater updater = worldStateKeyValueStorage.updater(); for (long blockNumber = markedBlockNumber - 1; blockNumber >= 0; blockNumber--) { final BlockHeader blockHeader = blockchain.getBlockHeader(blockNumber).get(); final Hash candidateStateRootHash = blockHeader.getStateRoot(); - if (!worldStateStorage.isWorldStateAvailable(candidateStateRootHash, null)) { + if (!worldStateKeyValueStorage.isWorldStateAvailable(candidateStateRootHash)) { break; } if (!isMarked(candidateStateRootHash)) { - updater.removeAccountStateTrieNode(null, candidateStateRootHash); + updater.removeAccountStateTrieNode(candidateStateRootHash); prunedNodeCount++; if (prunedNodeCount % operationsPerTransaction == 0) { updater.commit(); - updater = worldStateStorage.updater(); + updater = worldStateKeyValueStorage.updater(); } } } updater.commit(); // Sweep non-state-root nodes - prunedNodeCount += worldStateStorage.prune(this::isMarked); + prunedNodeCount += worldStateKeyValueStorage.prune(this::isMarked); sweptNodesCounter.inc(prunedNodeCount); clearMarks(); LOG.debug("Completed sweeping unused nodes"); } public void cleanup() { - worldStateStorage.removeNodeAddedListener(nodeAddedListenerId); + worldStateKeyValueStorage.removeNodeAddedListener(nodeAddedListenerId); clearMarks(); } @@ -242,7 +247,7 @@ private boolean isMarked(final byte[] key) { private MerkleTrie createStateTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), rootHash, Function.identity(), Function.identity()); @@ -250,7 +255,7 @@ private MerkleTrie createStateTrie(final Bytes32 rootHash) { private MerkleTrie createStorageTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.getAccountStorageTrieNode(null, location, hash), + (location, hash) -> worldStateKeyValueStorage.getAccountStorageTrieNode(hash), rootHash, Function.identity(), Function.identity()); @@ -265,7 +270,7 @@ private void processAccountState(final Bytes value, final ExecutorService execut } @VisibleForTesting - void markNode(final Bytes32 hash) { + public void markNode(final Bytes32 hash) { markThenMaybeFlush(() -> pendingMarks.add(hash), 1); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java index 9df312b0e4f..6e5457bede1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestWorldStateKeyValueStorage.java @@ -16,8 +16,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.trie.MerkleTrie; -import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; @@ -35,7 +34,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -public class ForestWorldStateKeyValueStorage implements WorldStateStorage { +public class ForestWorldStateKeyValueStorage implements WorldStateKeyValueStorage { private final Subscribers nodeAddedListeners = Subscribers.create(); private final KeyValueStorage keyValueStorage; @@ -50,8 +49,7 @@ public DataStorageFormat getDataStorageFormat() { return DataStorageFormat.FOREST; } - @Override - public Optional getCode(final Hash codeHash, final Hash accountHash) { + public Optional getCode(final Hash codeHash) { if (codeHash.equals(Hash.EMPTY)) { return Optional.of(Bytes.EMPTY); } else { @@ -59,14 +57,11 @@ public Optional getCode(final Hash codeHash, final Hash accountHash) { } } - @Override - public Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { + public Optional getAccountStateTrieNode(final Bytes32 nodeHash) { return getTrieNode(nodeHash); } - @Override - public Optional getAccountStorageTrieNode( - final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { + public Optional getAccountStorageTrieNode(final Bytes32 nodeHash) { return getTrieNode(nodeHash); } @@ -78,18 +73,12 @@ private Optional getTrieNode(final Bytes32 nodeHash) { } } - @Override - public Optional getTrieNodeUnsafe(final Bytes key) { - return keyValueStorage.get(key.toArrayUnsafe()).map(Bytes::wrap); - } - - @Override - public FlatDbMode getFlatDbMode() { - return FlatDbMode.NO_FLATTENED; + public boolean contains(final Bytes32 hash) { + // we don't have location info + return getNodeData(hash).isPresent(); } - @Override - public Optional getNodeData(final Bytes location, final Bytes32 hash) { + public Optional getNodeData(final Bytes32 hash) { if (hash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { return Optional.of(MerkleTrie.EMPTY_TRIE_NODE); } else if (hash.equals(Hash.EMPTY)) { @@ -99,9 +88,8 @@ public Optional getNodeData(final Bytes location, final Bytes32 hash) { } } - @Override - public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) { - return getAccountStateTrieNode(Bytes.EMPTY, rootHash).isPresent(); + public boolean isWorldStateAvailable(final Bytes32 rootHash) { + return getAccountStateTrieNode(rootHash).isPresent(); } @Override @@ -109,22 +97,11 @@ public void clear() { keyValueStorage.clear(); } - @Override - public void clearTrieLog() { - // nothing to do for forest - } - - @Override - public void clearFlatDatabase() { - // nothing to do for forest - } - @Override public Updater updater() { return new Updater(lock, keyValueStorage.startTransaction(), nodeAddedListeners); } - @Override public long prune(final Predicate inUseCheck) { final AtomicInteger prunedKeys = new AtomicInteger(0); try (final Stream entry = keyValueStorage.streamKeys()) { @@ -144,17 +121,15 @@ public long prune(final Predicate inUseCheck) { return prunedKeys.get(); } - @Override public long addNodeAddedListener(final NodesAddedListener listener) { return nodeAddedListeners.subscribe(listener); } - @Override public void removeNodeAddedListener(final long id) { nodeAddedListeners.unsubscribe(id); } - public static class Updater implements WorldStateStorage.Updater { + public static class Updater implements WorldStateKeyValueStorage.Updater { private final KeyValueStorageTransaction transaction; private final Subscribers nodeAddedListeners; @@ -170,9 +145,13 @@ public Updater( this.nodeAddedListeners = nodeAddedListeners; } - @Override - public WorldStateStorage.Updater putCode( - final Hash accountHash, final Hash codeHash, final Bytes code) { + public Updater putCode(final Bytes code) { + // Skip the hash calculation for empty code + final Hash codeHash = code.size() == 0 ? Hash.EMPTY : Hash.hash(code); + return putCode(codeHash, code); + } + + public Updater putCode(final Bytes32 codeHash, final Bytes code) { if (code.size() == 0) { // Don't save empty values return this; @@ -183,15 +162,11 @@ public WorldStateStorage.Updater putCode( return this; } - @Override - public WorldStateStorage.Updater saveWorldState( - final Bytes blockHash, final Bytes32 nodeHash, final Bytes node) { - return putAccountStateTrieNode(null, nodeHash, node); + public Updater saveWorldState(final Bytes32 nodeHash, final Bytes node) { + return putAccountStateTrieNode(nodeHash, node); } - @Override - public Updater putAccountStateTrieNode( - final Bytes location, final Bytes32 nodeHash, final Bytes node) { + public Updater putAccountStateTrieNode(final Bytes32 nodeHash, final Bytes node) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { // Don't save empty nodes return this; @@ -201,16 +176,12 @@ public Updater putAccountStateTrieNode( return this; } - @Override - public WorldStateStorage.Updater removeAccountStateTrieNode( - final Bytes location, final Bytes32 nodeHash) { + public WorldStateKeyValueStorage.Updater removeAccountStateTrieNode(final Bytes32 nodeHash) { transaction.remove(nodeHash.toArrayUnsafe()); return this; } - @Override - public Updater putAccountStorageTrieNode( - final Hash accountHash, final Bytes location, final Bytes32 nodeHash, final Bytes node) { + public Updater putAccountStorageTrieNode(final Bytes32 nodeHash, final Bytes node) { if (nodeHash.equals(MerkleTrie.EMPTY_TRIE_NODE_HASH)) { // Don't save empty nodes return this; @@ -231,7 +202,6 @@ public void commit() { } } - @Override public void rollback() { addedNodes.clear(); transaction.rollback(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldState.java index e9ba94c1a39..3dad0b04100 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldState.java @@ -23,10 +23,11 @@ import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -53,7 +54,7 @@ public class ForestMutableWorldState implements MutableWorldState { private final EvmConfiguration evmConfiguration; - private final WorldStateStorage worldStateStorage; + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage; private final WorldStatePreimageStorage preimageStorage; private final MerkleTrie accountStateTrie; @@ -63,18 +64,22 @@ public class ForestMutableWorldState implements MutableWorldState { private final Map newAccountKeyPreimages = new HashMap<>(); public ForestMutableWorldState( - final WorldStateStorage storage, + final WorldStateKeyValueStorage worldStateKeyValueStorage, final WorldStatePreimageStorage preimageStorage, final EvmConfiguration evmConfiguration) { - this(MerkleTrie.EMPTY_TRIE_NODE_HASH, storage, preimageStorage, evmConfiguration); + this( + MerkleTrie.EMPTY_TRIE_NODE_HASH, + worldStateKeyValueStorage, + preimageStorage, + evmConfiguration); } public ForestMutableWorldState( final Bytes32 rootHash, - final WorldStateStorage worldStateStorage, + final WorldStateKeyValueStorage worldStateKeyValueStorage, final WorldStatePreimageStorage preimageStorage, final EvmConfiguration evmConfiguration) { - this.worldStateStorage = worldStateStorage; + this.worldStateKeyValueStorage = (ForestWorldStateKeyValueStorage) worldStateKeyValueStorage; this.accountStateTrie = newAccountStateTrie(rootHash); this.preimageStorage = preimageStorage; this.evmConfiguration = evmConfiguration; @@ -88,8 +93,7 @@ public ForestMutableWorldState( if (!(worldState instanceof ForestMutableWorldState other)) { throw new UnsupportedOperationException(); } - - this.worldStateStorage = other.worldStateStorage; + this.worldStateKeyValueStorage = other.worldStateKeyValueStorage; this.preimageStorage = other.preimageStorage; this.accountStateTrie = newAccountStateTrie(other.accountStateTrie.getRootHash()); this.evmConfiguration = evmConfiguration; @@ -97,12 +101,15 @@ public ForestMutableWorldState( private MerkleTrie newAccountStateTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, rootHash, b -> b, b -> b); + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), + rootHash, + b -> b, + b -> b); } private MerkleTrie newAccountStorageTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.getAccountStorageTrieNode(null, location, hash), + (location, hash) -> worldStateKeyValueStorage.getAccountStorageTrieNode(hash), rootHash, b -> b, b -> b); @@ -168,19 +175,20 @@ public final boolean equals(final Object other) { @Override public void persist(final BlockHeader blockHeader) { - final WorldStateStorage.Updater stateUpdater = worldStateStorage.updater(); + final ForestWorldStateKeyValueStorage.Updater stateUpdater = + worldStateKeyValueStorage.updater(); // Store updated code for (final Bytes code : updatedAccountCode.values()) { - stateUpdater.putCode(null, code); + stateUpdater.putCode(code); } // Commit account storage tries for (final MerkleTrie updatedStorage : updatedStorageTries.values()) { updatedStorage.commit( - (location, hash, value) -> - stateUpdater.putAccountStorageTrieNode(null, location, hash, value)); + (location, hash, value) -> stateUpdater.putAccountStorageTrieNode(hash, value)); } // Commit account updates - accountStateTrie.commit(stateUpdater::putAccountStateTrieNode); + accountStateTrie.commit( + (location, hash, value) -> stateUpdater.putAccountStateTrieNode(hash, value)); // Persist preimages final WorldStatePreimageStorage.Updater preimageUpdater = preimageStorage.updater(); @@ -274,7 +282,7 @@ public Bytes getCode() { if (codeHash.equals(Hash.EMPTY)) { return Bytes.EMPTY; } - return worldStateStorage.getCode(codeHash, null).orElse(Bytes.EMPTY); + return worldStateKeyValueStorage.getCode(codeHash).orElse(Bytes.EMPTY); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java new file mode 100644 index 00000000000..3e848dce6ce --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateKeyValueStorage.java @@ -0,0 +1,38 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.worldstate; + +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.util.Collection; + +import org.apache.tuweni.bytes.Bytes32; + +public interface WorldStateKeyValueStorage { + + DataStorageFormat getDataStorageFormat(); + + Updater updater(); + + void clear(); + + interface NodesAddedListener { + void onNodesAdded(Collection nodeHash); + } + + interface Updater { + void commit(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java deleted file mode 100644 index a70a4982e51..00000000000 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorage.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.worldstate; - -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.function.Predicate; - -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; - -public interface WorldStateStorage { - - Optional getCode(Hash codeHash, Hash accountHash); - - Optional getAccountStateTrieNode(Bytes location, Bytes32 nodeHash); - - Optional getAccountStorageTrieNode(Hash accountHash, Bytes location, Bytes32 nodeHash); - - /** - * This method allows obtaining a TrieNode in an unsafe manner, without verifying the consistency - * of the obtained node. Checks such as node hash verification are not performed here. - * - * @param key of the trie node - * @return value of the trie node - */ - Optional getTrieNodeUnsafe(Bytes key); - - Optional getNodeData(Bytes location, Bytes32 hash); - - FlatDbMode getFlatDbMode(); - - boolean isWorldStateAvailable(Bytes32 rootHash, Hash blockHash); - - default boolean contains(final Bytes32 hash) { - // we don't have location info - return getNodeData(null, hash).isPresent(); - } - - /** - * Streams flat accounts within a specified range. - * - * @param startKeyHash The start key hash of the range. - * @param endKeyHash The end key hash of the range. - * @param max The maximum number of entries to stream. - * @return A map of flat accounts. (Empty map in this default implementation) - */ - default Map streamFlatAccounts( - final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { - return Collections.emptyMap(); - } - - /** - * Streams flat storages within a specified range. - * - * @param accountHash The account hash. - * @param startKeyHash The start key hash of the range. - * @param endKeyHash The end key hash of the range. - * @param max The maximum number of entries to stream. - * @return A map of flat storages. (Empty map in this default implementation) - */ - default Map streamFlatStorages( - final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) { - return Collections.emptyMap(); - } - - DataStorageFormat getDataStorageFormat(); - - void clear(); - - void clearTrieLog(); - - void clearFlatDatabase(); - - Updater updater(); - - long prune(Predicate inUseCheck); - - long addNodeAddedListener(NodesAddedListener listener); - - void removeNodeAddedListener(long id); - - interface Updater { - - Updater putCode(Hash accountHash, Hash nodeHash, Bytes code); - - default Updater putCode(final Hash accountHash, final Bytes code) { - // Skip the hash calculation for empty code - final Hash codeHash = code.size() == 0 ? Hash.EMPTY : Hash.hash(code); - return putCode(accountHash, codeHash, code); - } - - Updater saveWorldState(Bytes blockHash, Bytes32 nodeHash, Bytes node); - - Updater putAccountStateTrieNode(Bytes location, Bytes32 nodeHash, Bytes node); - - Updater removeAccountStateTrieNode(Bytes location, Bytes32 nodeHash); - - Updater putAccountStorageTrieNode( - Hash accountHash, Bytes location, Bytes32 nodeHash, Bytes node); - - void commit(); - - void rollback(); - } - - interface NodesAddedListener { - void onNodesAdded(Collection nodeHash); - } -} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java new file mode 100644 index 00000000000..f689410a9de --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java @@ -0,0 +1,155 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.worldstate; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +public class WorldStateStorageCoordinator { + private final WorldStateKeyValueStorage worldStateKeyValueStorage; + + public WorldStateStorageCoordinator(final WorldStateKeyValueStorage worldStateKeyValueStorage) { + this.worldStateKeyValueStorage = worldStateKeyValueStorage; + } + + public DataStorageFormat getDataStorageFormat() { + return worldStateKeyValueStorage.getDataStorageFormat(); + } + + public boolean isWorldStateAvailable(final Bytes32 nodeHash, final Hash blockHash) { + return applyForStrategy( + bonsai -> bonsai.isWorldStateAvailable(nodeHash, blockHash), + forest -> forest.isWorldStateAvailable(nodeHash)); + } + + public Optional getTrieNodeUnsafe(final Bytes key) { + return applyForStrategy( + bonsai -> bonsai.getTrieNodeUnsafe(key), + forest -> forest.getAccountStateTrieNode(Bytes32.wrap(key))); + } + + public Optional getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { + return applyForStrategy( + bonsai -> bonsai.getAccountStateTrieNode(location, nodeHash), + forest -> forest.getAccountStateTrieNode(nodeHash)); + } + + public Optional getAccountStorageTrieNode( + final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { + return applyForStrategy( + bonsai -> bonsai.getAccountStorageTrieNode(accountHash, location, nodeHash), + forest -> forest.getAccountStorageTrieNode(nodeHash)); + } + + @SuppressWarnings("unchecked") + public STRATEGY getStrategy( + final Class strategyClass) { + return (STRATEGY) worldStateKeyValueStorage; + } + + public boolean isMatchingFlatMode(final FlatDbMode flatDbMode) { + if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { + final BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorageStrategy = + (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage(); + return bonsaiWorldStateStorageStrategy.getFlatDbMode().equals(flatDbMode); + } + return false; + } + + public void applyOnMatchingFlatMode( + final FlatDbMode flatDbMode, final Consumer onStrategy) { + applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + worldStateKeyValueStorage -> { + final BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorageStrategy = + (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage(); + if (bonsaiWorldStateStorageStrategy.getFlatDbMode().equals(flatDbMode)) { + onStrategy.accept(bonsaiWorldStateStorageStrategy); + } + }); + } + + public void applyWhenFlatModeEnabled(final Consumer onStrategy) { + applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + worldStateKeyValueStorage -> { + final BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorageStrategy = + (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage(); + if (!bonsaiWorldStateStorageStrategy.getFlatDbMode().equals(FlatDbMode.NO_FLATTENED)) { + onStrategy.accept(bonsaiWorldStateStorageStrategy); + } + }); + } + + public void applyOnMatchingStrategy( + final DataStorageFormat dataStorageFormat, + final Consumer onStrategy) { + if (getDataStorageFormat().equals(dataStorageFormat)) { + onStrategy.accept(worldStateKeyValueStorage()); + } + } + + public RESPONSE applyForStrategy( + final Function onBonsai, + final Function onForest) { + if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { + return onBonsai.apply(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage())); + } else { + return onForest.apply(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage())); + } + } + + public void consumeForStrategy( + final Consumer onBonsai, + final Consumer onForest) { + if (getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { + onBonsai.accept(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage())); + } else { + onForest.accept(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage())); + } + } + + public static void applyForStrategy( + final WorldStateKeyValueStorage.Updater updater, + final Consumer onBonsai, + final Consumer onForest) { + if (updater instanceof BonsaiWorldStateKeyValueStorage.Updater) { + onBonsai.accept(((BonsaiWorldStateKeyValueStorage.Updater) updater)); + } else if (updater instanceof ForestWorldStateKeyValueStorage.Updater) { + onForest.accept(((ForestWorldStateKeyValueStorage.Updater) updater)); + } + } + + public WorldStateKeyValueStorage.Updater updater() { + return worldStateKeyValueStorage().updater(); + } + + public void clear() { + worldStateKeyValueStorage.clear(); + } + + public WorldStateKeyValueStorage worldStateKeyValueStorage() { + return worldStateKeyValueStorage; + } +} diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java index 3e4543e3b63..6626f4aada6 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java @@ -32,6 +32,7 @@ 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; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -79,7 +80,8 @@ public static MutableBlockchain createInMemoryBlockchain( public static ForestWorldStateArchive createInMemoryWorldStateArchive() { return new ForestWorldStateArchive( - new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()), + new WorldStateStorageCoordinator( + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage())), new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), EvmConfiguration.DEFAULT); } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryPrivacyStorageProvider.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryPrivacyStorageProvider.java index abecd974d87..d2521663b88 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryPrivacyStorageProvider.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryPrivacyStorageProvider.java @@ -24,8 +24,9 @@ import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -33,7 +34,8 @@ public class InMemoryPrivacyStorageProvider implements PrivacyStorageProvider { public static WorldStateArchive createInMemoryWorldStateArchive() { return new ForestWorldStateArchive( - new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()), + new WorldStateStorageCoordinator( + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage())), new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), EvmConfiguration.DEFAULT); } @@ -47,10 +49,15 @@ public static MutableWorldState createInMemoryWorldState() { } @Override - public WorldStateStorage createWorldStateStorage() { + public WorldStateKeyValueStorage createWorldStateStorage() { return new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); } + @Override + public WorldStateStorageCoordinator createWorldStateStorageCoordinator() { + return new WorldStateStorageCoordinator(createWorldStateStorage()); + } + @Override public WorldStatePreimageStorage createWorldStatePreimageStorage() { return new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()); diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TrieGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TrieGenerator.java index 757238a5d86..c549c66eb93 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TrieGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TrieGenerator.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.core; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -21,7 +23,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.List; import java.util.stream.Collectors; @@ -34,22 +37,23 @@ public class TrieGenerator { public static MerkleTrie generateTrie( - final WorldStateStorage worldStateStorage, final int nbAccounts) { + final WorldStateStorageCoordinator worldStateStorageCoordinator, final int nbAccounts) { return generateTrie( - worldStateStorage, + worldStateStorageCoordinator, IntStream.range(0, nbAccounts) .mapToObj(operand -> Hash.wrap(Bytes32.leftPad(Bytes.of(operand + 1)))) .collect(Collectors.toList())); } public static MerkleTrie generateTrie( - final WorldStateStorage worldStateStorage, final List accounts) { - final MerkleTrie accountStateTrie = emptyAccountStateTrie(worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator, final List accounts) { + final MerkleTrie accountStateTrie = + emptyAccountStateTrie(worldStateStorageCoordinator); // Add some storage values for (int i = 0; i < accounts.size(); i++) { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); final MerkleTrie storageTrie = - emptyStorageTrie(worldStateStorage, accounts.get(i)); + emptyStorageTrie(worldStateStorageCoordinator, accounts.get(i)); writeStorageValue(updater, storageTrie, accounts.get(i), UInt256.ONE, UInt256.valueOf(2L)); writeStorageValue( updater, storageTrie, accounts.get(i), UInt256.valueOf(2L), UInt256.valueOf(4L)); @@ -57,20 +61,36 @@ public static MerkleTrie generateTrie( updater, storageTrie, accounts.get(i), UInt256.valueOf(3L), UInt256.valueOf(6L)); int accountIndex = i; storageTrie.commit( - (location, hash, value) -> - updater.putAccountStorageTrieNode(accounts.get(accountIndex), location, hash, value)); + (location, hash, value) -> { + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStorageTrieNode( + accounts.get(accountIndex), location, hash, value); + }, + onForest -> { + onForest.putAccountStorageTrieNode(hash, value); + }); + }); final Bytes code = Bytes32.leftPad(Bytes.of(i + 10)); final Hash codeHash = Hash.hash(code); final StateTrieAccountValue accountValue = new StateTrieAccountValue(1L, Wei.of(2L), Hash.wrap(storageTrie.getRootHash()), codeHash); accountStateTrie.put(accounts.get(i), RLP.encode(accountValue::writeTo)); - if (worldStateStorage instanceof BonsaiWorldStateKeyValueStorage) { - ((BonsaiWorldStateKeyValueStorage.Updater) updater) - .putAccountInfoState(accounts.get(i), RLP.encode(accountValue::writeTo)); - updater.putCode(accounts.get(i), code); - } - accountStateTrie.commit(updater::putAccountStateTrieNode); - updater.putCode(codeHash, code); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountInfoState( + accounts.get(accountIndex), RLP.encode(accountValue::writeTo)); + accountStateTrie.commit(onBonsai::putAccountStateTrieNode); + onBonsai.putCode(accounts.get(accountIndex), codeHash, code); + }, + onForest -> { + accountStateTrie.commit( + (location, hash, value) -> onForest.putAccountStateTrieNode(hash, value)); + onForest.putCode(code); + }); + // Persist updates updater.commit(); } @@ -78,7 +98,7 @@ public static MerkleTrie generateTrie( } private static void writeStorageValue( - final WorldStateStorage.Updater updater, + final WorldStateKeyValueStorage.Updater updater, final MerkleTrie storageTrie, final Hash hash, final UInt256 key, @@ -101,17 +121,17 @@ private static Bytes encodeStorageValue(final UInt256 storageValue) { } public static MerkleTrie emptyStorageTrie( - final WorldStateStorage worldStateStorage, final Hash accountHash) { + final WorldStateStorageCoordinator worldStateStorageCoordinator, final Hash accountHash) { return new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateStorageCoordinator.getAccountStorageTrieNode(accountHash, location, hash), b -> b, b -> b); } public static MerkleTrie emptyAccountStateTrie( - final WorldStateStorage worldStateStorage) { + final WorldStateStorageCoordinator worldStateStorageCoordinator) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, b -> b, b -> b); + worldStateStorageCoordinator::getAccountStateTrieNode, b -> b, b -> b); } } 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 86d37238e27..f8fe794586f 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,7 +46,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -80,9 +80,12 @@ class BlockImportExceptionHandlingTest { protected final MutableBlockchain blockchain = mock(MutableBlockchain.class); private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); - private final WorldStateStorage worldStateStorage = - new BonsaiWorldStateKeyValueStorage( - storageProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator( + new BonsaiWorldStateKeyValueStorage( + storageProvider, + new NoOpMetricsSystem(), + DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)); private final WorldStateArchive worldStateArchive = // contains a BonsaiWorldState which we need to spy on. @@ -93,7 +96,8 @@ class BlockImportExceptionHandlingTest { spy( new BonsaiWorldState( (BonsaiWorldStateProvider) worldStateArchive, - (BonsaiWorldStateKeyValueStorage) worldStateStorage, + (BonsaiWorldStateKeyValueStorage) + worldStateStorageCoordinator.worldStateKeyValueStorage(), EvmConfiguration.DEFAULT)); private final BadBlockManager badBlockManager = new BadBlockManager(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java index e9e4bf91563..36123f5fd99 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateProofProviderTest.java @@ -24,7 +24,7 @@ import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.ArrayList; @@ -46,15 +46,15 @@ public class WorldStateProofProviderTest { private static final Address address = Address.fromHexString("0x1234567890123456789012345678901234567890"); - - private final WorldStateStorage worldStateStorage = + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); private WorldStateProofProvider worldStateProofProvider; @BeforeEach public void setup() { - worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); + worldStateProofProvider = + new WorldStateProofProvider(new WorldStateStorageCoordinator(worldStateKeyValueStorage)); } @Test @@ -68,19 +68,17 @@ public void getProofWhenWorldStateNotAvailable() { @Test public void getProofWhenWorldStateAvailable() { final Hash addressHash = address.addressHash(); - final MerkleTrie worldStateTrie = emptyWorldStateTrie(addressHash); + final MerkleTrie worldStateTrie = emptyWorldStateTrie(); final MerkleTrie storageTrie = emptyStorageTrie(); - final WorldStateStorage.Updater updater = worldStateStorage.updater(); + final ForestWorldStateKeyValueStorage.Updater updater = worldStateKeyValueStorage.updater(); // Add some storage values writeStorageValue(storageTrie, UInt256.ONE, UInt256.valueOf(2L)); writeStorageValue(storageTrie, UInt256.valueOf(2L), UInt256.valueOf(4L)); writeStorageValue(storageTrie, UInt256.valueOf(3L), UInt256.valueOf(6L)); // Save to Storage - storageTrie.commit( - (location, hash, value) -> - updater.putAccountStorageTrieNode(addressHash, location, hash, value)); + storageTrie.commit((location, hash, value) -> updater.putAccountStorageTrieNode(hash, value)); // Define account value final Hash codeHash = Hash.hash(Bytes.fromHexString("0x1122")); @@ -88,7 +86,7 @@ public void getProofWhenWorldStateAvailable() { new StateTrieAccountValue(1L, Wei.of(2L), Hash.wrap(storageTrie.getRootHash()), codeHash); // Save to storage worldStateTrie.put(addressHash, RLP.encode(accountValue::writeTo)); - worldStateTrie.commit(updater::putAccountStateTrieNode); + worldStateTrie.commit((location, hash, value) -> updater.putAccountStateTrieNode(hash, value)); // Persist updates updater.commit(); @@ -121,7 +119,7 @@ public void getProofWhenWorldStateAvailable() { @Test public void getProofWhenStateTrieAccountUnavailable() { - final MerkleTrie worldStateTrie = emptyWorldStateTrie(null); + final MerkleTrie worldStateTrie = emptyWorldStateTrie(); final Optional accountProof = worldStateProofProvider.getAccountProof( @@ -145,13 +143,14 @@ private Bytes encodeStorageValue(final UInt256 storageValue) { private MerkleTrie emptyStorageTrie() { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, b -> b, b -> b); + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), + b -> b, + b -> b); } - private MerkleTrie emptyWorldStateTrie(final Hash accountHash) { + private MerkleTrie emptyWorldStateTrie() { return new StoredMerklePatriciaTrie<>( - (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + (location, hash) -> worldStateKeyValueStorage.getAccountStorageTrieNode(hash), b -> b, b -> b); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java index 2bea39a8e4b..2132b6b48fc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/proof/WorldStateRangeProofProviderTest.java @@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.ArrayList; @@ -40,21 +40,22 @@ public class WorldStateRangeProofProviderTest { private static final Hash MAX_RANGE = Hash.fromHexString("0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - - private static final WorldStateStorage worldStateStorage = + private static final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + private WorldStateStorageCoordinator worldStateStorageCoordinator; private static WorldStateProofProvider worldStateProofProvider; @BeforeEach public void setup() { - worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + worldStateProofProvider = new WorldStateProofProvider(worldStateStorageCoordinator); } @Test public void rangeProofValidationNominalCase() { final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // collect accounts in range final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 10, Integer.MAX_VALUE); @@ -82,7 +83,8 @@ public void rangeProofValidationNominalCase() { @Test public void rangeProofValidationMissingAccount() { - MerkleTrie accountStateTrie = TrieGenerator.generateTrie(worldStateStorage, 15); + MerkleTrie accountStateTrie = + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // collect accounts in range final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 10, Integer.MAX_VALUE); @@ -119,7 +121,8 @@ public void rangeProofValidationMissingAccount() { @Test public void rangeProofValidationNoMonotonicIncreasing() { - MerkleTrie accountStateTrie = TrieGenerator.generateTrie(worldStateStorage, 15); + MerkleTrie accountStateTrie = + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // generate the invalid proof final RangeStorageEntriesCollector collector = @@ -155,7 +158,8 @@ public void rangeProofValidationNoMonotonicIncreasing() { @Test public void rangeProofValidationEmptyProof() { - MerkleTrie accountStateTrie = TrieGenerator.generateTrie(worldStateStorage, 15); + MerkleTrie accountStateTrie = + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // generate the invalid proof final RangeStorageEntriesCollector collector = @@ -182,7 +186,8 @@ public void rangeProofValidationEmptyProof() { @Test public void rangeProofValidationInvalidEmptyProof() { - MerkleTrie accountStateTrie = TrieGenerator.generateTrie(worldStateStorage, 15); + MerkleTrie accountStateTrie = + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // generate the invalid proof final RangeStorageEntriesCollector collector = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java index b8ad4a68a5d..33710bd4a4f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/AbstractIsolationTests.java @@ -69,6 +69,7 @@ import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.BesuConfiguration; @@ -94,7 +95,7 @@ public abstract class AbstractIsolationTests { protected BonsaiWorldStateProvider archive; - protected BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage; + protected WorldStateKeyValueStorage worldStateKeyValueStorage; protected ProtocolContext protocolContext; protected EthContext ethContext; protected EthScheduler ethScheduler = new DeterministicEthScheduler(); @@ -148,13 +149,12 @@ public abstract class AbstractIsolationTests { @BeforeEach public void createStorage() { - bonsaiWorldStateStorage = - (BonsaiWorldStateKeyValueStorage) - createKeyValueStorageProvider() - .createWorldStateStorage(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + worldStateKeyValueStorage = + createKeyValueStorageProvider() + .createWorldStateStorage(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); archive = new BonsaiWorldStateProvider( - bonsaiWorldStateStorage, + (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage, blockchain, Optional.of(16L), new CachedMerkleTrieLoader(new NoOpMetricsSystem()), diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiSnapshotIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiSnapshotIsolationTests.java index 20e34bb0903..ce983e10a9a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiSnapshotIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiSnapshotIsolationTests.java @@ -37,7 +37,7 @@ public void ensureTruncateDoesNotCauseSegfault() { var preTruncatedWorldState = archive.getMutable(genesisState.getBlock().getHeader(), false); assertThat(preTruncatedWorldState) .isPresent(); // really just assert that we have not segfaulted after truncating - bonsaiWorldStateStorage.clear(); + worldStateKeyValueStorage.clear(); var postTruncatedWorldState = archive.getMutable(genesisState.getBlock().getHeader(), false); assertThat(postTruncatedWorldState).isEmpty(); // assert that trying to access pre-worldstate does not segfault after truncating diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateArchiveTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProviderTest.java similarity index 98% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateArchiveTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProviderTest.java index d82174074a0..10d3381c7e0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateArchiveTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/BonsaiWorldStateProviderTest.java @@ -65,7 +65,7 @@ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) -class BonsaiWorldStateArchiveTest { +class BonsaiWorldStateProviderTest { final BlockHeaderTestFixture blockBuilder = new BlockHeaderTestFixture(); @Mock Blockchain blockchain; @@ -173,7 +173,7 @@ void testGetMutableWithStorageInconsistencyRollbackTheState() { .when(trieLogManager) .getTrieLogLayer(any(Hash.class)); - var worldStateStorage = + var worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), @@ -183,7 +183,7 @@ void testGetMutableWithStorageInconsistencyRollbackTheState() { new BonsaiWorldStateProvider( cachedWorldStorageManager, trieLogManager, - worldStateStorage, + worldStateKeyValueStorage, blockchain, new CachedMerkleTrieLoader(new NoOpMetricsSystem()), EvmConfiguration.DEFAULT)); @@ -202,7 +202,7 @@ void testGetMutableWithStorageInconsistencyRollbackTheState() { @Test void testGetMutableWithStorageConsistencyNotRollbackTheState() { - var worldStateStorage = + var worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), @@ -212,7 +212,7 @@ void testGetMutableWithStorageConsistencyNotRollbackTheState() { new BonsaiWorldStateProvider( cachedWorldStorageManager, trieLogManager, - worldStateStorage, + worldStateKeyValueStorage, blockchain, new CachedMerkleTrieLoader(new NoOpMetricsSystem()), EvmConfiguration.DEFAULT)); @@ -241,7 +241,7 @@ void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState() { .when(trieLogManager) .getTrieLogLayer(any(Hash.class)); - var worldStateStorage = + var worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), @@ -252,7 +252,7 @@ void testGetMutableWithStorageConsistencyToRollbackAndRollForwardTheState() { new BonsaiWorldStateProvider( cachedWorldStorageManager, trieLogManager, - worldStateStorage, + worldStateKeyValueStorage, blockchain, new CachedMerkleTrieLoader(new NoOpMetricsSystem()), EvmConfiguration.DEFAULT)); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/CachedMerkleTrieLoaderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/CachedMerkleTrieLoaderTest.java index 4d97691af16..d96c6990cb2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/CachedMerkleTrieLoaderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/CachedMerkleTrieLoaderTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.ArrayList; @@ -54,6 +55,8 @@ class CachedMerkleTrieLoaderTest { storageProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(inMemoryWorldState); final List
accounts = List.of(Address.fromHexString("0xdeadbeef"), Address.fromHexString("0xdeadbeee")); @@ -64,7 +67,7 @@ class CachedMerkleTrieLoaderTest { public void setup() { trie = TrieGenerator.generateTrie( - inMemoryWorldState, + worldStateStorageCoordinator, accounts.stream().map(Address::addressHash).collect(Collectors.toList())); merkleTrieLoader = new CachedMerkleTrieLoader(new NoOpMetricsSystem()); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/RollingImport.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/RollingImport.java index 4e7fcd5d564..a43fce8f402 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/RollingImport.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/RollingImport.java @@ -60,7 +60,7 @@ public static void main(final String[] arg) throws IOException { new BonsaiWorldStateKeyValueStorage( provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), EvmConfiguration.DEFAULT); - final SegmentedInMemoryKeyValueStorage worldStateStorage = + final SegmentedInMemoryKeyValueStorage worldStateKeyValueStorage = (SegmentedInMemoryKeyValueStorage) provider.getStorageBySegmentIdentifiers( List.of( @@ -128,7 +128,7 @@ provider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFI } } System.out.printf("Back to zero!%n"); - worldStateStorage.dump(System.out); + worldStateKeyValueStorage.dump(System.out); trieLogStorage.dump(System.out); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorageTest.java index eae7ecc7f20..911ff10005e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorageTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/storage/BonsaiWorldStateKeyValueStorageTest.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; @@ -117,21 +118,6 @@ void getAccountStorageTrieNode_returnsEmptyNode(final FlatDbMode flatDbMode) { .contains(MerkleTrie.EMPTY_TRIE_NODE); } - @ParameterizedTest - @MethodSource("flatDbMode") - void getNodeData_returnsEmptyValue(final FlatDbMode flatDbMode) { - setUp(flatDbMode); - assertThat(storage.getNodeData(null, null)).isEmpty(); - } - - @ParameterizedTest - @MethodSource("flatDbModeAndCodeStorageMode") - void getNodeData_returnsEmptyNode( - final FlatDbMode flatDbMode, final boolean accountHashCodeStorage) { - setUp(flatDbMode, accountHashCodeStorage); - assertThat(storage.getNodeData(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)).isEmpty(); - } - @ParameterizedTest @MethodSource("flatDbModeAndCodeStorageMode") void getCode_saveAndGetSpecialValues( @@ -232,15 +218,15 @@ void getAccount_notLoadFromTrieWhenEmptyAndFlatDbFullMode(final FlatDbMode flatD setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); - - final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); + final WorldStateStorageCoordinator coordinator = new WorldStateStorageCoordinator(storage); + final MerkleTrie trie = TrieGenerator.generateTrie(coordinator, 1); final TreeMap accounts = (TreeMap) trie.entriesFrom(root -> StorageEntriesCollector.collectEntries(root, Hash.ZERO, 1)); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater .getWorldStateTransaction() .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); @@ -264,13 +250,14 @@ void getAccount_loadFromTrieWhenEmptyAndFlatDbPartialMode(final FlatDbMode flatD setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); - final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); + final WorldStateStorageCoordinator coordinator = new WorldStateStorageCoordinator(storage); + final MerkleTrie trie = TrieGenerator.generateTrie(coordinator, 1); final TreeMap accounts = (TreeMap) trie.entriesFrom(root -> StorageEntriesCollector.collectEntries(root, Hash.ZERO, 1)); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater .getWorldStateTransaction() .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); @@ -293,14 +280,14 @@ void shouldUsePartialDBStrategyAfterDowngradingMode(final FlatDbMode flatDbMode) setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); - - final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); + final WorldStateStorageCoordinator coordinator = new WorldStateStorageCoordinator(storage); + final MerkleTrie trie = TrieGenerator.generateTrie(coordinator, 1); final TreeMap accounts = (TreeMap) trie.entriesFrom(root -> StorageEntriesCollector.collectEntries(root, Hash.ZERO, 1)); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater .getWorldStateTransaction() .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); @@ -325,7 +312,8 @@ void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode flatDbMode setUp(flatDbMode); Assumptions.assumeTrue(flatDbMode == FlatDbMode.PARTIAL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); - final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); + final WorldStateStorageCoordinator coordinator = new WorldStateStorageCoordinator(storage); + final MerkleTrie trie = TrieGenerator.generateTrie(coordinator, 1); final TreeMap accounts = (TreeMap) trie.entriesFrom(root -> StorageEntriesCollector.collectEntries(root, Hash.ZERO, 1)); @@ -347,7 +335,7 @@ void getStorage_loadFromTrieWhenEmptyWithPartialMode(final FlatDbMode flatDbMode root -> StorageEntriesCollector.collectEntries(root, Hash.ZERO, 1)); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater .getWorldStateTransaction() .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); @@ -375,10 +363,11 @@ void getStorage_loadFromTrieWhenEmptyWithFullMode(final FlatDbMode flatDbMode) { Assumptions.assumeTrue(flatDbMode == FlatDbMode.FULL); final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); storage.upgradeToFullFlatDbMode(); - final MerkleTrie trie = TrieGenerator.generateTrie(storage, 1); + final WorldStateStorageCoordinator coordinator = new WorldStateStorageCoordinator(storage); + final MerkleTrie trie = TrieGenerator.generateTrie(coordinator, 1); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater .getWorldStateTransaction() .put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, trie.getRootHash().toArrayUnsafe()); @@ -395,7 +384,7 @@ void clear_reloadFlatDbStrategy(final FlatDbMode flatDbMode) { final BonsaiWorldStateKeyValueStorage storage = spy(emptyStorage()); // save world state root hash - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); updater.putAccountInfoState(Hash.ZERO, Bytes32.random()).commit(); assertThat(storage.getAccount(Hash.ZERO)).isNotEmpty(); @@ -419,8 +408,8 @@ void reconcilesNonConflictingUpdaters(final FlatDbMode flatDbMode) { final Bytes bytesB = Bytes.fromHexString("0x1234"); final Bytes bytesC = Bytes.fromHexString("0x123456"); - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updaterA = storage.updater(); - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updaterB = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updaterA = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updaterB = storage.updater(); updaterA.putCode(accountHashA, bytesA); updaterB.putCode(accountHashB, bytesA); @@ -446,7 +435,7 @@ void isWorldStateAvailable_defaultIsFalse(final FlatDbMode flatDbMode) { void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) { setUp(flatDbMode); - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); final Bytes rootHashKey = Bytes32.fromHexString("0x01"); updater .getWorldStateTransaction() @@ -461,7 +450,7 @@ void isWorldStateAvailable_StateAvailableByRootHash(final FlatDbMode flatDbMode) void isWorldStateAvailable_afterCallingSaveWorldstate(final FlatDbMode flatDbMode) { setUp(flatDbMode); - final BonsaiWorldStateKeyValueStorage.BonsaiUpdater updater = storage.updater(); + final BonsaiWorldStateKeyValueStorage.Updater updater = storage.updater(); final Bytes blockHash = Bytes32.fromHexString("0x01"); final Bytes32 nodeHashKey = Bytes32.fromHexString("0x02"); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateTest.java index c3ec2e18b37..f875f098bdc 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/bonsai/worldview/BonsaiWorldStateTest.java @@ -45,7 +45,7 @@ @ExtendWith(MockitoExtension.class) class BonsaiWorldStateTest { @Mock BonsaiWorldStateUpdateAccumulator bonsaiWorldStateUpdateAccumulator; - @Mock BonsaiWorldStateKeyValueStorage.BonsaiUpdater bonsaiUpdater; + @Mock BonsaiWorldStateKeyValueStorage.Updater bonsaiUpdater; @Mock Blockchain blockchain; @Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPrunerTest.java index dffc26e1933..1287800d9c3 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/pruner/MarkSweepPrunerTest.java @@ -36,7 +36,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -66,11 +66,11 @@ class MarkSweepPrunerTest { private final NoOpMetricsSystem metricsSystem = new NoOpMetricsSystem(); private final Map> hashValueStore = spy(new HashMap<>()); private final InMemoryKeyValueStorage stateStorage = new TestInMemoryStorage(hashValueStore); - private final WorldStateStorage worldStateStorage = + private final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = spy(new ForestWorldStateKeyValueStorage(stateStorage)); private final WorldStateArchive worldStateArchive = new ForestWorldStateArchive( - worldStateStorage, + new WorldStateStorageCoordinator(worldStateKeyValueStorage), new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), EvmConfiguration.DEFAULT); private final InMemoryKeyValueStorage markStorage = new InMemoryKeyValueStorage(); @@ -80,7 +80,7 @@ class MarkSweepPrunerTest { @Test void mark_marksAllExpectedNodes() { final MarkSweepPruner pruner = - new MarkSweepPruner(worldStateStorage, blockchain, markStorage, metricsSystem); + new MarkSweepPruner(worldStateKeyValueStorage, blockchain, markStorage, metricsSystem); // Generate accounts and save corresponding state root final int numBlocks = 15; @@ -129,7 +129,7 @@ void mark_marksAllExpectedNodes() { @Test void sweepBefore_shouldSweepStateRootFirst() { final MarkSweepPruner pruner = - new MarkSweepPruner(worldStateStorage, blockchain, markStorage, metricsSystem); + new MarkSweepPruner(worldStateKeyValueStorage, blockchain, markStorage, metricsSystem); // Generate accounts and save corresponding state root final int numBlocks = 15; @@ -154,17 +154,17 @@ void sweepBefore_shouldSweepStateRootFirst() { stateRoots.forEach( stateRoot -> { final InOrder thisRootsOrdering = - inOrder(worldStateStorage, hashValueStore, worldStateStorage); - thisRootsOrdering.verify(worldStateStorage).isWorldStateAvailable(stateRoot, null); + inOrder(worldStateKeyValueStorage, hashValueStore, worldStateKeyValueStorage); + thisRootsOrdering.verify(worldStateKeyValueStorage).isWorldStateAvailable(stateRoot); thisRootsOrdering.verify(hashValueStore).keySet(); - thisRootsOrdering.verify(worldStateStorage).prune(any()); + thisRootsOrdering.verify(worldStateKeyValueStorage).prune(any()); }); } @Test void sweepBefore_shouldNotRemoveMarkedStateRoots() { final MarkSweepPruner pruner = - new MarkSweepPruner(worldStateStorage, blockchain, markStorage, metricsSystem); + new MarkSweepPruner(worldStateKeyValueStorage, blockchain, markStorage, metricsSystem); // Generate accounts and save corresponding state root final int numBlocks = 15; @@ -193,10 +193,10 @@ void sweepBefore_shouldNotRemoveMarkedStateRoots() { stateRoots.forEach( stateRoot -> { final InOrder thisRootsOrdering = - inOrder(worldStateStorage, hashValueStore, worldStateStorage); - thisRootsOrdering.verify(worldStateStorage).isWorldStateAvailable(stateRoot, null); + inOrder(worldStateKeyValueStorage, hashValueStore, worldStateKeyValueStorage); + thisRootsOrdering.verify(worldStateKeyValueStorage).isWorldStateAvailable(stateRoot); thisRootsOrdering.verify(hashValueStore).keySet(); - thisRootsOrdering.verify(worldStateStorage).prune(any()); + thisRootsOrdering.verify(worldStateKeyValueStorage).prune(any()); }); assertThat(stateStorage.containsKey(markedRoot.toArray())).isTrue(); @@ -269,7 +269,7 @@ private void collectTrieNodes(final MerkleTrie trie, final Set createStateTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + (location, hash) -> worldStateKeyValueStorage.getAccountStateTrieNode(hash), rootHash, Function.identity(), Function.identity()); @@ -277,7 +277,7 @@ private MerkleTrie createStateTrie(final Bytes32 rootHash) { private MerkleTrie createStorageTrie(final Bytes32 rootHash) { return new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.getAccountStorageTrieNode(null, location, hash), + (location, hash) -> worldStateKeyValueStorage.getAccountStorageTrieNode(hash), rootHash, Function.identity(), Function.identity()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestKeyValueStorageWorldStateStorageTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestKeyValueStorageWorldStateStorageTest.java index bc505cd0e5d..08dfc86d5c0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestKeyValueStorageWorldStateStorageTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestKeyValueStorageWorldStateStorageTest.java @@ -30,53 +30,52 @@ public class ForestKeyValueStorageWorldStateStorageTest { @Test public void getCode_returnsEmpty() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - assertThat(storage.getCode(Hash.EMPTY, null)).contains(Bytes.EMPTY); + assertThat(storage.getCode(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getAccountStateTrieNode_returnsEmptyNode() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getAccountStateTrieNode(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); } @Test public void getAccountStorageTrieNode_returnsEmptyNode() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - assertThat( - storage.getAccountStorageTrieNode(null, Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getAccountStorageTrieNode(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); } @Test public void getNodeData_returnsEmptyValue() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - assertThat(storage.getNodeData(null, Hash.EMPTY)).contains(Bytes.EMPTY); + assertThat(storage.getNodeData(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getNodeData_returnsEmptyNode() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - assertThat(storage.getNodeData(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getNodeData(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); } @Test public void getCode_saveAndGetSpecialValues() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); - storage.updater().putCode(null, MerkleTrie.EMPTY_TRIE_NODE).putCode(null, Bytes.EMPTY).commit(); + storage.updater().putCode(MerkleTrie.EMPTY_TRIE_NODE).putCode(Bytes.EMPTY).commit(); - assertThat(storage.getCode(Hash.EMPTY_TRIE_HASH, null)).contains(MerkleTrie.EMPTY_TRIE_NODE); - assertThat(storage.getCode(Hash.EMPTY, null)).contains(Bytes.EMPTY); + assertThat(storage.getCode(Hash.EMPTY_TRIE_HASH)).contains(MerkleTrie.EMPTY_TRIE_NODE); + assertThat(storage.getCode(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getCode_saveAndGetRegularValue() { final Bytes bytes = Bytes.fromHexString("0x123456"); final ForestWorldStateKeyValueStorage storage = emptyStorage(); - storage.updater().putCode(null, bytes).commit(); + storage.updater().putCode(bytes).commit(); - assertThat(storage.getCode(Hash.hash(bytes), null)).contains(bytes); + assertThat(storage.getCode(Hash.hash(bytes))).contains(bytes); } @Test @@ -84,23 +83,22 @@ public void getAccountStateTrieNode_saveAndGetSpecialValues() { final ForestWorldStateKeyValueStorage storage = emptyStorage(); storage .updater() - .putAccountStateTrieNode( - null, Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) - .putAccountStateTrieNode(null, Hash.hash(Bytes.EMPTY), Bytes.EMPTY) + .putAccountStateTrieNode(Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) + .putAccountStateTrieNode(Hash.hash(Bytes.EMPTY), Bytes.EMPTY) .commit(); - assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getAccountStateTrieNode(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); - assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); + assertThat(storage.getAccountStateTrieNode(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getAccountStateTrieNode_saveAndGetRegularValue() { final Bytes bytes = Bytes.fromHexString("0x123456"); final ForestWorldStateKeyValueStorage storage = emptyStorage(); - storage.updater().putAccountStateTrieNode(null, Hash.hash(bytes), bytes).commit(); + storage.updater().putAccountStateTrieNode(Hash.hash(bytes), bytes).commit(); - assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, Hash.hash(bytes))).contains(bytes); + assertThat(storage.getAccountStateTrieNode(Hash.hash(bytes))).contains(bytes); } @Test @@ -109,24 +107,22 @@ public void getAccountStorageTrieNode_saveAndGetSpecialValues() { storage .updater() .putAccountStorageTrieNode( - null, null, Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) - .putAccountStorageTrieNode(null, null, Hash.hash(Bytes.EMPTY), Bytes.EMPTY) + Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) + .putAccountStorageTrieNode(Hash.hash(Bytes.EMPTY), Bytes.EMPTY) .commit(); - assertThat( - storage.getAccountStorageTrieNode(null, Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getAccountStorageTrieNode(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); - assertThat(storage.getAccountStorageTrieNode(null, Bytes.EMPTY, Hash.EMPTY)) - .contains(Bytes.EMPTY); + assertThat(storage.getAccountStorageTrieNode(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getAccountStorageTrieNode_saveAndGetRegularValue() { final Bytes bytes = Bytes.fromHexString("0x123456"); final ForestWorldStateKeyValueStorage storage = emptyStorage(); - storage.updater().putAccountStorageTrieNode(null, null, Hash.hash(bytes), bytes).commit(); + storage.updater().putAccountStorageTrieNode(Hash.hash(bytes), bytes).commit(); - assertThat(storage.getAccountStateTrieNode(Bytes.EMPTY, Hash.hash(bytes))).contains(bytes); + assertThat(storage.getAccountStateTrieNode(Hash.hash(bytes))).contains(bytes); } @Test @@ -135,22 +131,22 @@ public void getNodeData_saveAndGetSpecialValues() { storage .updater() .putAccountStorageTrieNode( - null, null, Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) - .putAccountStorageTrieNode(null, null, Hash.hash(Bytes.EMPTY), Bytes.EMPTY) + Hash.hash(MerkleTrie.EMPTY_TRIE_NODE), MerkleTrie.EMPTY_TRIE_NODE) + .putAccountStorageTrieNode(Hash.hash(Bytes.EMPTY), Bytes.EMPTY) .commit(); - assertThat(storage.getNodeData(Bytes.EMPTY, MerkleTrie.EMPTY_TRIE_NODE_HASH)) + assertThat(storage.getNodeData(MerkleTrie.EMPTY_TRIE_NODE_HASH)) .contains(MerkleTrie.EMPTY_TRIE_NODE); - assertThat(storage.getNodeData(Bytes.EMPTY, Hash.EMPTY)).contains(Bytes.EMPTY); + assertThat(storage.getNodeData(Hash.EMPTY)).contains(Bytes.EMPTY); } @Test public void getNodeData_saveAndGetRegularValue() { final Bytes bytes = Bytes.fromHexString("0x123456"); final ForestWorldStateKeyValueStorage storage = emptyStorage(); - storage.updater().putAccountStorageTrieNode(null, null, Hash.hash(bytes), bytes).commit(); + storage.updater().putAccountStorageTrieNode(Hash.hash(bytes), bytes).commit(); - assertThat(storage.getNodeData(null, Hash.hash(bytes))).contains(bytes); + assertThat(storage.getNodeData(Hash.hash(bytes))).contains(bytes); } @Test @@ -163,27 +159,27 @@ public void reconcilesNonConflictingUpdaters() { final Updater updaterA = storage.updater(); final Updater updaterB = storage.updater(); - updaterA.putCode(null, bytesA); - updaterB.putCode(null, bytesA); - updaterB.putCode(null, bytesB); - updaterA.putCode(null, bytesC); + updaterA.putCode(bytesA); + updaterB.putCode(bytesA); + updaterB.putCode(bytesB); + updaterA.putCode(bytesC); updaterA.commit(); updaterB.commit(); - assertThat(storage.getCode(Hash.hash(bytesA), null)).contains(bytesA); - assertThat(storage.getCode(Hash.hash(bytesB), null)).contains(bytesB); - assertThat(storage.getCode(Hash.hash(bytesC), null)).contains(bytesC); + assertThat(storage.getCode(Hash.hash(bytesA))).contains(bytesA); + assertThat(storage.getCode(Hash.hash(bytesB))).contains(bytesB); + assertThat(storage.getCode(Hash.hash(bytesC))).contains(bytesC); } @Test public void isWorldStateAvailable_defaultIsFalse() { - assertThat(emptyStorage().isWorldStateAvailable(UInt256.valueOf(1), null)).isFalse(); + assertThat(emptyStorage().isWorldStateAvailable(UInt256.valueOf(1))).isFalse(); } @Test public void isWorldStateAvailable_emptyTrieStateAlwaysAvailable() { - assertThat(emptyStorage().isWorldStateAvailable(Hash.EMPTY_TRIE_HASH, null)).isTrue(); + assertThat(emptyStorage().isWorldStateAvailable(Hash.EMPTY_TRIE_HASH)).isTrue(); } private ForestWorldStateKeyValueStorage emptyStorage() { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldStateTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldStateTest.java index dec41cd8d60..359b076338f 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldStateTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/worldview/ForestMutableWorldStateTest.java @@ -263,12 +263,12 @@ void commitAndPersist() { assertThat(worldState.get(ADDRESS).getBalance()).isEqualTo(newBalance); // Check that storage is empty before persisting - assertThat(kvWorldStateStorage.isWorldStateAvailable(worldState.rootHash(), null)).isFalse(); + assertThat(kvWorldStateStorage.isWorldStateAvailable(worldState.rootHash())).isFalse(); // Persist and re-run assertions worldState.persist(null); - assertThat(kvWorldStateStorage.isWorldStateAvailable(worldState.rootHash(), null)).isTrue(); + assertThat(kvWorldStateStorage.isWorldStateAvailable(worldState.rootHash())).isTrue(); assertThat(worldState.rootHash()).isEqualTo(expectedRootHash); assertThat(worldState.get(ADDRESS)).isNotNull(); assertThat(worldState.get(ADDRESS).getBalance()).isEqualTo(newBalance); 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 fb7f36038a0..1fc9046ec72 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 @@ -39,9 +39,10 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.rocksdb.RocksDBKeyValueStorageFactory; @@ -77,7 +78,7 @@ public class WorldStateDownloaderBenchmark { private BlockHeader blockHeader; private final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); private WorldStateDownloader worldStateDownloader; - private WorldStateStorage worldStateStorage; + private WorldStateStorageCoordinator worldStateStorageCoordinator; private RespondingEthPeer peer; private Responder responder; private InMemoryTasksPriorityQueues pendingRequests; @@ -106,14 +107,14 @@ public void setUpUnchangedState() { final StorageProvider storageProvider = createKeyValueStorageProvider(tempDir, tempDir.resolve("database")); - worldStateStorage = - storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_CONFIG); + worldStateStorageCoordinator = + storageProvider.createWorldStateStorageCoordinator(DataStorageConfiguration.DEFAULT_CONFIG); pendingRequests = new InMemoryTasksPriorityQueues<>(); worldStateDownloader = new FastWorldStateDownloader( ethContext, - worldStateStorage, + worldStateStorageCoordinator, pendingRequests, syncConfig.getWorldStateHashCountPerRequest(), syncConfig.getWorldStateRequestParallelism(), @@ -153,7 +154,9 @@ public Optional downloadWorldState() { peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone()); result.getNow(null); final Optional rootData = - worldStateStorage.getNodeData(Bytes.EMPTY, blockHeader.getStateRoot()); + worldStateStorageCoordinator + .getStrategy(ForestWorldStateKeyValueStorage.class) + .getNodeData(blockHeader.getStateRoot()); if (rootData.isEmpty()) { throw new IllegalStateException("World state download did not complete."); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 00647142009..34c906bd90d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -36,7 +36,7 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.services.BesuEvents.SyncStatusListener; @@ -77,7 +77,7 @@ public DefaultSynchronizer( final SynchronizerConfiguration syncConfig, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final BlockBroadcaster blockBroadcaster, final Optional maybePruner, final EthContext ethContext, @@ -139,7 +139,7 @@ public DefaultSynchronizer( protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); } else if (SyncMode.isCheckpointSync(syncConfig.getSyncMode())) { @@ -154,7 +154,7 @@ public DefaultSynchronizer( protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); } else { @@ -169,7 +169,7 @@ public DefaultSynchronizer( protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java index ff8187d8d21..1177fe42f8b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.trie.CompactEncoding; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; @@ -60,7 +60,7 @@ public static Optional> createCheckpointDownloader( final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock) { @@ -104,7 +104,7 @@ public static Optional> createCheckpointDownloader( fastSyncActions = new FastSyncActions( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, @@ -121,7 +121,7 @@ public static Optional> createCheckpointDownloader( fastSyncActions = new CheckpointSyncActions( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, @@ -142,7 +142,7 @@ public static Optional> createCheckpointDownloader( ethContext, snapContext, protocolContext, - worldStateStorage, + worldStateStorageCoordinator, snapTaskCollection, syncConfig.getSnapSyncConfiguration(), syncConfig.getWorldStateRequestParallelism(), @@ -153,7 +153,7 @@ public static Optional> createCheckpointDownloader( final FastSyncDownloader fastSyncDownloader = new SnapSyncDownloader( fastSyncActions, - worldStateStorage, + worldStateStorageCoordinator, snapWorldStateDownloader, fastSyncStateStorage, snapTaskCollection, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java index 8159ccdaa02..7319e9e44f7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java @@ -23,13 +23,13 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; public class CheckpointSyncActions extends FastSyncActions { public CheckpointSyncActions( final SynchronizerConfiguration syncConfig, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, @@ -38,7 +38,7 @@ public CheckpointSyncActions( final MetricsSystem metricsSystem) { super( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, @@ -51,7 +51,7 @@ public CheckpointSyncActions( public ChainDownloader createChainDownloader(final FastSyncState currentState) { return CheckpointSyncChainDownloader.create( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java index 356ad0d078d..1b53c25004f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java @@ -23,14 +23,14 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.SyncTargetManager; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; public class CheckpointSyncChainDownloader extends FastSyncChainDownloader { public static ChainDownloader create( final SynchronizerConfiguration config, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, @@ -41,7 +41,7 @@ public static ChainDownloader create( final SyncTargetManager syncTargetManager = new SyncTargetManager( config, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java index d7d3523538b..52d384acf6e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByHashTask; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; @@ -43,7 +43,7 @@ public class FastSyncActions { private static final Logger LOG = LoggerFactory.getLogger(FastSyncActions.class); protected final SynchronizerConfiguration syncConfig; - protected final WorldStateStorage worldStateStorage; + protected final WorldStateStorageCoordinator worldStateStorageCoordinator; protected final ProtocolSchedule protocolSchedule; protected final ProtocolContext protocolContext; protected final EthContext ethContext; @@ -55,7 +55,7 @@ public class FastSyncActions { public FastSyncActions( final SynchronizerConfiguration syncConfig, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, @@ -63,7 +63,7 @@ public FastSyncActions( final PivotBlockSelector pivotBlockSelector, final MetricsSystem metricsSystem) { this.syncConfig = syncConfig; - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.ethContext = ethContext; @@ -158,7 +158,7 @@ private FastSyncState updateStats(final FastSyncState fastSyncState) { public ChainDownloader createChainDownloader(final FastSyncState currentState) { return FastSyncChainDownloader.create( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java index ae49cfdec29..36f56ccfd8b 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; public class FastSyncChainDownloader { @@ -30,7 +30,7 @@ protected FastSyncChainDownloader() {} public static ChainDownloader create( final SynchronizerConfiguration config, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, @@ -41,7 +41,7 @@ public static ChainDownloader create( final SyncTargetManager syncTargetManager = new SyncTargetManager( config, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java index dc56cac5397..87a021136e2 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java @@ -21,7 +21,8 @@ import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements; import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.tasks.TaskCollection; import org.hyperledger.besu.util.ExceptionUtils; @@ -47,7 +48,7 @@ public class FastSyncDownloader { @SuppressWarnings("PrivateStaticFinalLoggers") protected final Logger LOG = LoggerFactory.getLogger(getClass()); - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final WorldStateDownloader worldStateDownloader; private final TaskCollection taskCollection; private final Path fastSyncDataDirectory; @@ -60,14 +61,14 @@ public class FastSyncDownloader { public FastSyncDownloader( final FastSyncActions fastSyncActions, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateDownloader worldStateDownloader, final FastSyncStateStorage fastSyncStateStorage, final TaskCollection taskCollection, final Path fastSyncDataDirectory, final FastSyncState initialFastSyncState) { this.fastSyncActions = fastSyncActions; - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.worldStateDownloader = worldStateDownloader; this.fastSyncStateStorage = fastSyncStateStorage; this.taskCollection = taskCollection; @@ -84,11 +85,15 @@ public CompletableFuture start() { } protected CompletableFuture start(final FastSyncState fastSyncState) { - if (worldStateStorage.getDataStorageFormat().equals(DataStorageFormat.BONSAI)) { - LOG.info("Clearing bonsai flat account db"); - worldStateStorage.clearFlatDatabase(); - worldStateStorage.clearTrieLog(); - } + worldStateStorageCoordinator.applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + worldStateKeyValueStorage -> { + BonsaiWorldStateKeyValueStorage onBonsai = + (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage; + LOG.info("Clearing bonsai flat account db"); + onBonsai.clearFlatDatabase(); + onBonsai.clearTrieLog(); + }); LOG.debug("Start sync with initial sync state {}", fastSyncState); return findPivotBlock(fastSyncState, fss -> downloadChainAndWorldState(fastSyncActions, fss)); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/SyncTargetManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/SyncTargetManager.java index 6d49212c402..548cce6eadc 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/SyncTargetManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/SyncTargetManager.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.tasks.RetryingGetHeaderFromPeerByNumberTask; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.messages.DisconnectMessage.DisconnectReason; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.List; @@ -42,7 +42,7 @@ public class SyncTargetManager extends AbstractSyncTargetManager { private static final Logger LOG = LoggerFactory.getLogger(SyncTargetManager.class); - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final ProtocolSchedule protocolSchedule; private final ProtocolContext protocolContext; private final EthContext ethContext; @@ -55,14 +55,14 @@ public class SyncTargetManager extends AbstractSyncTargetManager { public SyncTargetManager( final SynchronizerConfiguration config, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, final MetricsSystem metricsSystem, final FastSyncState fastSyncState) { super(config, protocolSchedule, protocolContext, ethContext, metricsSystem); - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.ethContext = ethContext; @@ -176,7 +176,7 @@ public boolean shouldContinueDownloading() { return true; } } - return !worldStateStorage.isWorldStateAvailable( + return !worldStateStorageCoordinator.isWorldStateAvailable( pivotBlockHeader.getStateRoot(), pivotBlockHeader.getBlockHash()); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/AccountTrieNodeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/AccountTrieNodeDataRequest.java index 78af77054de..71855a997f4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/AccountTrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/AccountTrieNodeDataRequest.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.trie.CompactEncoding; import org.hyperledger.besu.ethereum.trie.MerkleTrie; -import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.Optional; import java.util.stream.Stream; @@ -38,16 +38,24 @@ class AccountTrieNodeDataRequest extends TrieNodeDataRequest { } @Override - protected void doPersist(final Updater updater) { - updater.putAccountStateTrieNode(getLocation().orElse(Bytes.EMPTY), getHash(), getData()); + protected void doPersist(final WorldStateKeyValueStorage.Updater updater) { + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStateTrieNode(getLocation().orElse(Bytes.EMPTY), getHash(), getData()); + }, + onForest -> { + onForest.putAccountStateTrieNode(getHash(), getData()); + }); } @Override - public Optional getExistingData(final WorldStateStorage worldStateStorage) { + public Optional getExistingData( + final WorldStateStorageCoordinator worldStateKeyValueStorage) { return getLocation() .flatMap( location -> - worldStateStorage + worldStateKeyValueStorage .getAccountStateTrieNode(location, getHash()) .filter(data -> Hash.hash(data).equals(getHash()))); } @@ -60,7 +68,7 @@ protected NodeDataRequest createChildNodeDataRequest( @Override protected Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateKeyValueStorage, final Optional location, final Bytes path, final Bytes value) { @@ -73,11 +81,11 @@ protected Stream getRequestsFromTrieNodeValue( Bytes32.wrap( CompactEncoding.pathToBytes( Bytes.concatenate(getLocation().orElse(Bytes.EMPTY), path))))); - if (!worldStateStorage.getFlatDbMode().equals(FlatDbMode.NO_FLATTENED)) { - ((BonsaiWorldStateKeyValueStorage.Updater) worldStateStorage.updater()) - .putAccountInfoState(accountHash.get(), value) - .commit(); - } + + worldStateKeyValueStorage.applyWhenFlatModeEnabled( + onBonsai -> { + onBonsai.updater().putAccountInfoState(accountHash.get(), value).commit(); + }); // Add code, if appropriate if (!accountValue.getCodeHash().equals(Hash.EMPTY)) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CodeNodeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CodeNodeDataRequest.java index 0a8672ef795..714f6066f64 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CodeNodeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/CodeNodeDataRequest.java @@ -14,10 +14,12 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.rlp.RLPOutput; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.Optional; import java.util.stream.Stream; @@ -34,21 +36,36 @@ class CodeNodeDataRequest extends NodeDataRequest { } @Override - protected void doPersist(final Updater updater) { - updater.putCode(accountHash.orElse(Hash.EMPTY), getHash(), getData()); + protected void doPersist(final WorldStateKeyValueStorage.Updater updater) { + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putCode(accountHash.orElse(Hash.EMPTY), getHash(), getData()); + }, + onForest -> { + onForest.putCode(getHash(), getData()); + }); } @Override - public Stream getChildRequests(final WorldStateStorage worldStateStorage) { + public Stream getChildRequests( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { // Code nodes have nothing further to download return Stream.empty(); } @Override - public Optional getExistingData(final WorldStateStorage worldStateStorage) { - return worldStateStorage - .getCode(getHash(), accountHash.orElse(Hash.EMPTY)) - .filter(codeBytes -> Hash.hash(codeBytes).equals(getHash())); + public Optional getExistingData( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { + return worldStateStorageCoordinator.applyForStrategy( + onBonsai -> { + return onBonsai + .getCode(getHash(), accountHash.orElse(Hash.EMPTY)) + .filter(codeBytes -> Hash.hash(codeBytes).equals(getHash())); + }, + onForest -> { + return onForest.getCode(getHash()); + }); } public Optional getAccountHash() { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java index da520d88b55..bf9f28db6ce 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java @@ -28,8 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; @@ -59,7 +58,7 @@ public static Optional> create( final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock) { @@ -90,23 +89,25 @@ public static Optional> create( return Optional.empty(); } - if (worldStateStorage instanceof BonsaiWorldStateKeyValueStorage) { - worldStateStorage.clearFlatDatabase(); - } else { - final Path queueDataDir = fastSyncDataDirectory.resolve("statequeue"); - if (queueDataDir.toFile().exists()) { - LOG.warn( - "Fast sync is picking up after old fast sync version. Pruning the world state and starting from scratch."); - clearOldFastSyncWorldStateData(worldStateStorage, queueDataDir); - } - } + worldStateStorageCoordinator.consumeForStrategy( + onBonsai -> { + onBonsai.clearFlatDatabase(); + }, + onForest -> { + final Path queueDataDir = fastSyncDataDirectory.resolve("statequeue"); + if (queueDataDir.toFile().exists()) { + LOG.warn( + "Fast sync is picking up after old fast sync version. Pruning the world state and starting from scratch."); + clearOldFastSyncWorldStateData(worldStateStorageCoordinator, queueDataDir); + } + }); final InMemoryTasksPriorityQueues taskCollection = createWorldStateDownloaderTaskCollection( metricsSystem, syncConfig.getWorldStateTaskCacheSize()); final WorldStateDownloader worldStateDownloader = new FastWorldStateDownloader( ethContext, - worldStateStorage, + worldStateStorageCoordinator, taskCollection, syncConfig.getWorldStateHashCountPerRequest(), syncConfig.getWorldStateRequestParallelism(), @@ -118,14 +119,14 @@ public static Optional> create( new FastSyncDownloader<>( new FastSyncActions( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, syncState, pivotBlockSelector, metricsSystem), - worldStateStorage, + worldStateStorageCoordinator, worldStateDownloader, fastSyncStateStorage, taskCollection, @@ -136,8 +137,8 @@ public static Optional> create( } private static void clearOldFastSyncWorldStateData( - final WorldStateStorage worldStateStorage, final Path queueDataDir) { - worldStateStorage.clear(); + final WorldStateStorageCoordinator worldStateKeyValueStorage, final Path queueDataDir) { + worldStateKeyValueStorage.clear(); try (final Stream stream = Files.list(queueDataDir); ) { stream.forEach(FastDownloaderFactory::deleteFile); deleteFile(queueDataDir); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadState.java index 0703c93ef89..3bd6a76c79e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadState.java @@ -14,10 +14,12 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; import java.time.Clock; @@ -31,13 +33,13 @@ public class FastWorldDownloadState extends WorldDownloadState private static final Logger LOG = LoggerFactory.getLogger(FastWorldDownloadState.class); public FastWorldDownloadState( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final InMemoryTasksPriorityQueues pendingRequests, final int maxRequestsWithoutProgress, final long minMillisBeforeStalling, final Clock clock) { super( - worldStateStorage, + worldStateStorageCoordinator, pendingRequests, maxRequestsWithoutProgress, minMillisBeforeStalling, @@ -53,8 +55,15 @@ public synchronized boolean checkCompletion(final BlockHeader header) { header.getStateRoot(), Optional.of(Bytes.EMPTY))); return false; } - final Updater updater = worldStateStorage.updater(); - updater.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); + }, + onForest -> { + onForest.saveWorldState(header.getStateRoot(), rootNodeData); + }); updater.commit(); internalFuture.complete(null); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloader.java index 4bdbae71cee..559ade5900c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloader.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncActions; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; @@ -48,7 +48,7 @@ public class FastWorldStateDownloader implements WorldStateDownloader { private final int hashCountPerRequest; private final int maxOutstandingRequests; private final int maxNodeRequestsWithoutProgress; - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final AtomicReference downloadState = new AtomicReference<>(); @@ -56,7 +56,7 @@ public class FastWorldStateDownloader implements WorldStateDownloader { public FastWorldStateDownloader( final EthContext ethContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final InMemoryTasksPriorityQueues taskCollection, final int hashCountPerRequest, final int maxOutstandingRequests, @@ -65,7 +65,7 @@ public FastWorldStateDownloader( final Clock clock, final MetricsSystem metricsSystem) { this.ethContext = ethContext; - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.taskCollection = taskCollection; this.hashCountPerRequest = hashCountPerRequest; this.maxOutstandingRequests = maxOutstandingRequests; @@ -117,7 +117,7 @@ public CompletableFuture run( final BlockHeader header = fastSyncState.getPivotBlockHeader().get(); final Hash stateRoot = header.getStateRoot(); - if (worldStateStorage.isWorldStateAvailable(stateRoot, header.getHash())) { + if (worldStateStorageCoordinator.isWorldStateAvailable(stateRoot, header.getHash())) { LOG.info( "World state already available for block {} ({}). State root {}", header.getNumber(), @@ -133,7 +133,7 @@ public CompletableFuture run( final FastWorldDownloadState newDownloadState = new FastWorldDownloadState( - worldStateStorage, + worldStateStorageCoordinator, taskCollection, maxNodeRequestsWithoutProgress, minMillisBeforeStalling, @@ -151,9 +151,9 @@ public CompletableFuture run( FastWorldStateDownloadProcess.builder() .hashCountPerRequest(hashCountPerRequest) .maxOutstandingRequests(maxOutstandingRequests) - .loadLocalDataStep(new LoadLocalDataStep(worldStateStorage, metricsSystem)) + .loadLocalDataStep(new LoadLocalDataStep(worldStateStorageCoordinator, metricsSystem)) .requestDataStep(new RequestDataStep(ethContext, metricsSystem)) - .persistDataStep(new PersistDataStep(worldStateStorage)) + .persistDataStep(new PersistDataStep(worldStateStorageCoordinator)) .completeTaskStep(maybeCompleteTask.get()) .downloadState(newDownloadState) .pivotBlockHeader(header) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStep.java index f56780f5259..d84b92af2df 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStep.java @@ -14,7 +14,8 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.metrics.Counter; @@ -28,12 +29,13 @@ public class LoadLocalDataStep { - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final Counter existingNodeCounter; public LoadLocalDataStep( - final WorldStateStorage worldStateStorage, final MetricsSystem metricsSystem) { - this.worldStateStorage = worldStateStorage; + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final MetricsSystem metricsSystem) { + this.worldStateStorageCoordinator = worldStateStorageCoordinator; existingNodeCounter = metricsSystem.createCounter( BesuMetricCategory.SYNCHRONIZER, @@ -44,12 +46,12 @@ public LoadLocalDataStep( public Stream> loadLocalData( final Task task, final Pipe> completedTasks) { final NodeDataRequest request = task.getData(); - final Optional existingData = request.getExistingData(worldStateStorage); + final Optional existingData = request.getExistingData(worldStateStorageCoordinator); if (existingData.isPresent()) { existingNodeCounter.inc(); request.setData(existingData.get()); request.setRequiresPersisting(false); - final WorldStateStorage.Updater updater = worldStateStorage.updater(); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); request.persist(updater); updater.commit(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequest.java index 2ff8429316e..a5dda8524f0 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/NodeDataRequest.java @@ -20,7 +20,8 @@ import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloaderException; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPOutput; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.TasksPriorityProvider; import java.util.Optional; @@ -103,7 +104,7 @@ public NodeDataRequest setRequiresPersisting(final boolean requiresPersisting) { return this; } - public final void persist(final WorldStateStorage.Updater updater) { + public final void persist(final WorldStateKeyValueStorage.Updater updater) { if (pendingChildren.get() > 0) { return; // we do nothing. Our last child will eventually persist us. } @@ -115,7 +116,7 @@ public final void persist(final WorldStateStorage.Updater updater) { parent -> parent.saveParent(updater), () -> LOG.warn("Missing a parent for {}", this.hash)); } - private void saveParent(final WorldStateStorage.Updater updater) { + private void saveParent(final WorldStateKeyValueStorage.Updater updater) { if (pendingChildren.decrementAndGet() == 0) { persist(updater); } @@ -127,11 +128,13 @@ private int incrementChildren() { protected abstract void writeTo(final RLPOutput out); - protected abstract void doPersist(final WorldStateStorage.Updater updater); + protected abstract void doPersist(final WorldStateKeyValueStorage.Updater updater); - public abstract Stream getChildRequests(WorldStateStorage worldStateStorage); + public abstract Stream getChildRequests( + WorldStateStorageCoordinator worldStateStorageCoordinator); - public abstract Optional getExistingData(final WorldStateStorage worldStateStorage); + public abstract Optional getExistingData( + final WorldStateStorageCoordinator worldStateStorageCoordinator); protected void registerParent(final NodeDataRequest parent) { if (this.possibleParent.isPresent()) { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java index 1ab202ee6ce..fe83a12ec42 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java @@ -20,8 +20,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; @@ -34,10 +34,10 @@ public class PersistDataStep { private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; - public PersistDataStep(final WorldStateStorage worldStateStorage) { - this.worldStateStorage = worldStateStorage; + public PersistDataStep(final WorldStateStorageCoordinator worldStateStorageCoordinator) { + this.worldStateStorageCoordinator = worldStateStorageCoordinator; } public List> persist( @@ -45,7 +45,7 @@ public List> persist( final BlockHeader blockHeader, final WorldDownloadState downloadState) { try { - final Updater updater = worldStateStorage.updater(); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); tasks.stream() .map( task -> { @@ -88,6 +88,6 @@ private boolean isRootState(final BlockHeader blockHeader, final NodeDataRequest private void enqueueChildren( final Task task, final WorldDownloadState downloadState) { final NodeDataRequest request = task.getData(); - downloadState.enqueueRequests(request.getChildRequests(worldStateStorage)); + downloadState.enqueueRequests(request.getChildRequests(worldStateStorageCoordinator)); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/StorageTrieNodeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/StorageTrieNodeDataRequest.java index 1a78eede605..9b1dc0839c1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/StorageTrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/StorageTrieNodeDataRequest.java @@ -14,13 +14,13 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.trie.CompactEncoding; -import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.Optional; import java.util.stream.Stream; @@ -40,20 +40,31 @@ class StorageTrieNodeDataRequest extends TrieNodeDataRequest { } @Override - protected void doPersist(final Updater updater) { - updater.putAccountStorageTrieNode( - accountHash.orElse(Hash.EMPTY), getLocation().orElse(Bytes.EMPTY), getHash(), getData()); + protected void doPersist(final WorldStateKeyValueStorage.Updater updater) { + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStorageTrieNode( + accountHash.orElse(Hash.EMPTY), + getLocation().orElse(Bytes.EMPTY), + getHash(), + getData()); + }, + onForest -> { + onForest.putAccountStorageTrieNode(getHash(), getData()); + }); } @Override - public Optional getExistingData(final WorldStateStorage worldStateStorage) { + public Optional getExistingData( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { return getAccountHash() .flatMap( accountHash -> getLocation() .flatMap( location -> - worldStateStorage + worldStateStorageCoordinator .getAccountStorageTrieNode(accountHash, location, getHash()) .filter(data -> Hash.hash(data).equals(getHash())))); } @@ -66,18 +77,21 @@ protected NodeDataRequest createChildNodeDataRequest( @Override protected Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final Optional location, final Bytes path, final Bytes value) { - if (!worldStateStorage.getFlatDbMode().equals(FlatDbMode.NO_FLATTENED)) { - ((BonsaiWorldStateKeyValueStorage.Updater) worldStateStorage.updater()) - .putStorageValueBySlotHash( - accountHash.get(), - getSlotHash(location, path), - Bytes32.leftPad(RLP.decodeValue(value))) - .commit(); - } + + worldStateStorageCoordinator.applyWhenFlatModeEnabled( + worldStateKeyValueStorage -> { + worldStateKeyValueStorage + .updater() + .putStorageValueBySlotHash( + accountHash.get(), + getSlotHash(location, path), + Bytes32.leftPad(RLP.decodeValue(value))) + .commit(); + }); return Stream.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/TrieNodeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/TrieNodeDataRequest.java index 2761db14329..c9ea51ce0f4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/TrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/TrieNodeDataRequest.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.trie.Node; import org.hyperledger.besu.ethereum.trie.patricia.TrieNodeDecoder; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.List; import java.util.Objects; @@ -34,7 +34,8 @@ protected TrieNodeDataRequest( } @Override - public Stream getChildRequests(final WorldStateStorage worldStateStorage) { + public Stream getChildRequests( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { if (getData() == null) { // If this node hasn't been downloaded yet, we can't return any child data return Stream.empty(); @@ -53,7 +54,10 @@ public Stream getChildRequests(final WorldStateStorage worldSta .map( value -> getRequestsFromTrieNodeValue( - worldStateStorage, node.getLocation(), node.getPath(), value)) + worldStateStorageCoordinator, + node.getLocation(), + node.getPath(), + value)) .orElseGet(Stream::empty); } }) @@ -68,7 +72,7 @@ protected abstract NodeDataRequest createChildNodeDataRequest( final Hash childHash, final Optional location); protected abstract Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final Optional location, final Bytes path, final Bytes value); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java index c24dbf6037d..394023aba06 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java @@ -20,7 +20,8 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.exception.StorageException; @@ -38,7 +39,7 @@ public class LoadLocalDataStep { private static final Logger LOG = LoggerFactory.getLogger(LoadLocalDataStep.class); - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final SnapWorldDownloadState downloadState; private final SnapSyncProcessState snapSyncState; @@ -46,12 +47,12 @@ public class LoadLocalDataStep { private final Counter existingNodeCounter; public LoadLocalDataStep( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapWorldDownloadState downloadState, final SnapSyncConfiguration snapSyncConfiguration, final MetricsSystem metricsSystem, final SnapSyncProcessState snapSyncState) { - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.downloadState = downloadState; this.snapSyncConfiguration = snapSyncConfiguration; existingNodeCounter = @@ -68,16 +69,21 @@ public Stream> loadLocalDataTrieNode( // check if node is already stored in the worldstate try { if (snapSyncState.hasPivotBlockHeader()) { - Optional existingData = request.getExistingData(downloadState, worldStateStorage); + Optional existingData = request.getExistingData(worldStateStorageCoordinator); if (existingData.isPresent()) { existingNodeCounter.inc(); request.setData(existingData.get()); request.setRequiresPersisting(false); - final WorldStateStorage.Updater updater = worldStateStorage.updater(); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); request.persist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + worldStateStorageCoordinator, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); updater.commit(); - downloadState.enqueueRequests(request.getRootStorageRequests(worldStateStorage)); + downloadState.enqueueRequests( + request.getRootStorageRequests(worldStateStorageCoordinator)); completedTasks.put(task); return Stream.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java index 9b72d056046..264b29017d7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java @@ -21,7 +21,8 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; @@ -35,30 +36,31 @@ public class PersistDataStep { private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); private final SnapSyncProcessState snapSyncState; - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final SnapWorldDownloadState downloadState; private final SnapSyncConfiguration snapSyncConfiguration; public PersistDataStep( final SnapSyncProcessState snapSyncState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapWorldDownloadState downloadState, final SnapSyncConfiguration snapSyncConfiguration) { this.snapSyncState = snapSyncState; - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.downloadState = downloadState; this.snapSyncConfiguration = snapSyncConfiguration; } public List> persist(final List> tasks) { try { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); for (Task task : tasks) { if (task.getData().isResponseReceived()) { // enqueue child requests final Stream childRequests = - task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState); + task.getData() + .getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState); if (!(task.getData() instanceof TrieNodeHealingRequest)) { enqueueChildren(childRequests); } else { @@ -73,7 +75,7 @@ public List> persist(final List> tas final int persistedNodes = task.getData() .persist( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, @@ -115,15 +117,21 @@ public List> persist(final List> tas */ public List> healFlatDatabase(final List> tasks) { final BonsaiWorldStateKeyValueStorage.Updater updater = - (BonsaiWorldStateKeyValueStorage.Updater) worldStateStorage.updater(); + (BonsaiWorldStateKeyValueStorage.Updater) worldStateStorageCoordinator.updater(); for (Task task : tasks) { // heal and/or persist task.getData() - .persist(worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + .persist( + worldStateStorageCoordinator, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); // enqueue child requests, these will be the right part of the ranges to complete if we have // not healed all the range enqueueChildren( - task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState)); + task.getData() + .getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState)); } updater.commit(); return tasks; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java index f78ffe3af9a..fdde0a5eea9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RequestDataStep.java @@ -31,7 +31,8 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageFlatDatabaseHealingRangeRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.tasks.Task; @@ -50,7 +51,7 @@ public class RequestDataStep { - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final SnapSyncProcessState fastSyncState; private final SnapWorldDownloadState downloadState; private final SnapSyncConfiguration snapSyncConfiguration; @@ -60,18 +61,18 @@ public class RequestDataStep { public RequestDataStep( final EthContext ethContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState fastSyncState, final SnapWorldDownloadState downloadState, final SnapSyncConfiguration snapSyncConfiguration, final MetricsSystem metricsSystem) { - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.fastSyncState = fastSyncState; this.downloadState = downloadState; this.snapSyncConfiguration = snapSyncConfiguration; this.metricsSystem = metricsSystem; this.ethContext = ethContext; - this.worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); + this.worldStateProofProvider = new WorldStateProofProvider(worldStateStorageCoordinator); } public CompletableFuture> requestAccount( @@ -230,12 +231,18 @@ public CompletableFuture> requestLocalFlatAccounts( final BlockHeader blockHeader = fastSyncState.getPivotBlockHeader().get(); // retrieve accounts from flat database - final TreeMap accounts = - (TreeMap) - worldStateStorage.streamFlatAccounts( - accountDataRequest.getStartKeyHash(), - accountDataRequest.getEndKeyHash(), - snapSyncConfiguration.getLocalFlatAccountCountToHealPerRequest()); + final TreeMap accounts = new TreeMap<>(); + + worldStateStorageCoordinator.applyOnMatchingFlatMode( + FlatDbMode.FULL, + onBonsai -> { + accounts.putAll( + onBonsai.streamFlatAccounts( + accountDataRequest.getStartKeyHash(), + accountDataRequest.getEndKeyHash(), + snapSyncConfiguration.getLocalFlatAccountCountToHealPerRequest())); + }); + final List proofs = new ArrayList<>(); if (!accounts.isEmpty()) { // generate range proof if accounts are present @@ -270,13 +277,18 @@ public CompletableFuture> requestLocalFlatStorages( storageDataRequest.setRootHash(blockHeader.getStateRoot()); // retrieve slots from flat database - final TreeMap slots = - (TreeMap) - worldStateStorage.streamFlatStorages( - storageDataRequest.getAccountHash(), - storageDataRequest.getStartKeyHash(), - storageDataRequest.getEndKeyHash(), - snapSyncConfiguration.getLocalFlatStorageCountToHealPerRequest()); + final TreeMap slots = new TreeMap<>(); + worldStateStorageCoordinator.applyOnMatchingFlatMode( + FlatDbMode.FULL, + onBonsai -> { + slots.putAll( + onBonsai.streamFlatStorages( + storageDataRequest.getAccountHash(), + storageDataRequest.getStartKeyHash(), + storageDataRequest.getEndKeyHash(), + snapSyncConfiguration.getLocalFlatStorageCountToHealPerRequest())); + }); + final List proofs = new ArrayList<>(); if (!slots.isEmpty()) { // generate range proof if slots are present diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java index 65fb117788e..44077ade5b1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java @@ -32,7 +32,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.trie.CompactEncoding; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; @@ -56,7 +56,7 @@ public static Optional> createSnapDownloader( final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock) { @@ -105,7 +105,7 @@ public static Optional> createSnapDownloader( ethContext, snapContext, protocolContext, - worldStateStorage, + worldStateStorageCoordinator, snapTaskCollection, syncConfig.getSnapSyncConfiguration(), syncConfig.getWorldStateRequestParallelism(), @@ -117,14 +117,14 @@ public static Optional> createSnapDownloader( new SnapSyncDownloader( new FastSyncActions( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, syncState, pivotBlockSelector, metricsSystem), - worldStateStorage, + worldStateStorageCoordinator, snapWorldStateDownloader, fastSyncStateStorage, snapTaskCollection, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapSyncDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapSyncDownloader.java index 32c2dc23c0b..581905b44b3 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapSyncDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapSyncDownloader.java @@ -20,7 +20,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncStateStorage; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.TaskCollection; import java.nio.file.Path; @@ -30,7 +30,7 @@ public class SnapSyncDownloader extends FastSyncDownloader { public SnapSyncDownloader( final FastSyncActions fastSyncActions, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateDownloader worldStateDownloader, final FastSyncStateStorage fastSyncStateStorage, final TaskCollection taskCollection, @@ -38,7 +38,7 @@ public SnapSyncDownloader( final FastSyncState initialFastSyncState) { super( fastSyncActions, - worldStateStorage, + worldStateStorageCoordinator, worldStateDownloader, fastSyncStateStorage, taskCollection, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java index 76d31562106..cb6ed53ce69 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java @@ -16,6 +16,7 @@ import static org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest.createAccountFlatHealingRangeRequest; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest.createAccountTrieNodeDataRequest; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -28,9 +29,12 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountFlatDatabaseHealingRangeRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageFlatDatabaseHealingRangeRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.tasks.InMemoryTaskQueue; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; import org.hyperledger.besu.services.tasks.Task; @@ -86,7 +90,7 @@ public class SnapWorldDownloadState extends WorldDownloadState private final SnapSyncMetricsManager metricsManager; public SnapWorldDownloadState( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncStatePersistenceManager snapContext, final Blockchain blockchain, final SnapSyncProcessState snapSyncState, @@ -96,7 +100,7 @@ public SnapWorldDownloadState( final SnapSyncMetricsManager metricsManager, final Clock clock) { super( - worldStateStorage, + worldStateStorageCoordinator, pendingRequests, maxRequestsWithoutProgress, minMillisBeforeStalling, @@ -191,15 +195,22 @@ else if (pivotBlockSelector.isBlockchainBehind()) { // If the flat database healing process is not in progress and the flat database mode is // FULL if (!snapSyncState.isHealFlatDatabaseInProgress() - && worldStateStorage.getFlatDbMode().equals(FlatDbMode.FULL)) { - // Start the flat database healing process + && worldStateStorageCoordinator.isMatchingFlatMode(FlatDbMode.FULL)) { startFlatDatabaseHeal(header); } // If the flat database healing process is in progress or the flat database mode is not FULL else { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - updater.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); + final WorldStateKeyValueStorage.Updater updater = worldStateStorageCoordinator.updater(); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData); + }, + onForest -> { + onForest.saveWorldState(header.getStateRoot(), rootNodeData); + }); updater.commit(); + // Notify that the snap sync has completed metricsManager.notifySnapSyncCompleted(); // Clear the snap context @@ -242,8 +253,14 @@ public synchronized void startTrieHeal() { /** Method to reload the healing process of the trie */ public synchronized void reloadTrieHeal() { // Clear the flat database and trie log from the world state storage if needed - worldStateStorage.clearFlatDatabase(); - worldStateStorage.clearTrieLog(); + worldStateStorageCoordinator.applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + worldStateKeyValueStorage -> { + final BonsaiWorldStateKeyValueStorage strategy = + worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class); + strategy.clearFlatDatabase(); + strategy.clearTrieLog(); + }); // Clear pending trie node and code requests pendingTrieNodeRequests.clear(); pendingCodeRequests.clear(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java index 877559f6b7e..b3dae73d934 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java @@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -63,7 +63,7 @@ public class SnapWorldStateDownloader implements WorldStateDownloader { private final int maxOutstandingRequests; private final int maxNodeRequestsWithoutProgress; private final ProtocolContext protocolContext; - private final WorldStateStorage worldStateStorage; + private final WorldStateStorageCoordinator worldStateStorageCoordinator; private final AtomicReference downloadState = new AtomicReference<>(); @@ -71,7 +71,7 @@ public SnapWorldStateDownloader( final EthContext ethContext, final SnapSyncStatePersistenceManager snapContext, final ProtocolContext protocolContext, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final InMemoryTasksPriorityQueues snapTaskCollection, final SnapSyncConfiguration snapSyncConfiguration, final int maxOutstandingRequests, @@ -81,7 +81,7 @@ public SnapWorldStateDownloader( final MetricsSystem metricsSystem) { this.ethContext = ethContext; this.protocolContext = protocolContext; - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.snapContext = snapContext; this.snapTaskCollection = snapTaskCollection; this.snapSyncConfiguration = snapSyncConfiguration; @@ -138,7 +138,7 @@ public CompletableFuture run( final SnapWorldDownloadState newDownloadState = new SnapWorldDownloadState( - worldStateStorage, + worldStateStorageCoordinator, snapContext, protocolContext.getBlockchain(), snapSyncState, @@ -167,19 +167,30 @@ public CompletableFuture run( }); } else if (!snapContext.getAccountsHealingList().isEmpty()) { // restart only the heal step snapSyncState.setHealTrieStatus(true); - worldStateStorage.clearFlatDatabase(); - worldStateStorage.clearTrieLog(); + worldStateStorageCoordinator.applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + strategy -> { + BonsaiWorldStateKeyValueStorage onBonsai = (BonsaiWorldStateKeyValueStorage) strategy; + onBonsai.clearFlatDatabase(); + onBonsai.clearTrieLog(); + }); + newDownloadState.setAccountsHealingList(inconsistentAccounts); newDownloadState.enqueueRequest( SnapDataRequest.createAccountTrieNodeDataRequest( stateRoot, Bytes.EMPTY, snapContext.getAccountsHealingList())); } else { // start from scratch - worldStateStorage.clear(); + worldStateStorageCoordinator.clear(); // we have to upgrade to full flat db mode if we are in bonsai mode - if (worldStateStorage.getDataStorageFormat().equals(DataStorageFormat.BONSAI) - && snapSyncConfiguration.isFlatDbHealingEnabled()) { - ((BonsaiWorldStateKeyValueStorage) worldStateStorage).upgradeToFullFlatDbMode(); + if (snapSyncConfiguration.isFlatDbHealingEnabled()) { + worldStateStorageCoordinator.applyOnMatchingStrategy( + DataStorageFormat.BONSAI, + strategy -> { + BonsaiWorldStateKeyValueStorage onBonsai = + (BonsaiWorldStateKeyValueStorage) strategy; + onBonsai.upgradeToFullFlatDbMode(); + }); } ranges.forEach( (key, value) -> @@ -205,7 +216,7 @@ public CompletableFuture run( .dynamicPivotBlockSelector(dynamicPivotBlockManager) .loadLocalDataStep( new LoadLocalDataStep( - worldStateStorage, + worldStateStorageCoordinator, newDownloadState, snapSyncConfiguration, metricsSystem, @@ -213,14 +224,17 @@ public CompletableFuture run( .requestDataStep( new RequestDataStep( ethContext, - worldStateStorage, + worldStateStorageCoordinator, snapSyncState, newDownloadState, snapSyncConfiguration, metricsSystem)) .persistDataStep( new PersistDataStep( - snapSyncState, worldStateStorage, newDownloadState, snapSyncConfiguration)) + snapSyncState, + worldStateStorageCoordinator, + newDownloadState, + snapSyncConfiguration)) .completeTaskStep(maybeCompleteTask.get()) .downloadState(newDownloadState) .fastSyncState(snapSyncState) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java index acf8adc4aa9..7829ad75eb8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RequestType.ACCOUNT_RANGE; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncMetricsManager.Step.DOWNLOAD; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.StackTrie.FlatDatabaseUpdater.noop; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncConfiguration; @@ -33,8 +34,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.ArrayList; import java.util.List; @@ -42,6 +43,7 @@ import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; @@ -104,8 +106,8 @@ protected AccountRangeDataRequest( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { @@ -120,19 +122,31 @@ protected int doPersist( final AtomicInteger nbNodesSaved = new AtomicInteger(); final NodeUpdater nodeUpdater = (location, hash, value) -> { - updater.putAccountStateTrieNode(location, hash, value); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStateTrieNode(location, hash, value); + }, + onForest -> { + onForest.putAccountStateTrieNode(hash, value); + }); nbNodesSaved.getAndIncrement(); }; - StackTrie.FlatDatabaseUpdater flatDatabaseUpdater = noop(); - if (worldStateStorage.getFlatDbMode().equals(FlatDbMode.FULL)) { - // we have a flat DB only with Bonsai - flatDatabaseUpdater = - (key, value) -> - ((BonsaiWorldStateKeyValueStorage.BonsaiUpdater) updater) - .putAccountInfoState(Hash.wrap(key), value); - } - stackTrie.commit(flatDatabaseUpdater, nodeUpdater); + final AtomicReference flatDatabaseUpdater = + new AtomicReference<>(noop()); + + // we have a flat DB only with Bonsai + worldStateStorageCoordinator.applyOnMatchingFlatMode( + FlatDbMode.FULL, + bonsaiWorldStateStorageStrategy -> { + flatDatabaseUpdater.set( + (key, value) -> + ((BonsaiWorldStateKeyValueStorage.Updater) updater) + .putAccountInfoState(Hash.wrap(key), value)); + }); + + stackTrie.commit(flatDatabaseUpdater.get(), nodeUpdater); downloadState.getMetricsManager().notifyAccountsDownloaded(stackTrie.getElementsCount().get()); @@ -162,7 +176,7 @@ public boolean isResponseReceived() { @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { final List childRequests = new ArrayList<>(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java index 5db5ec0211e..47add2ff8f8 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java @@ -15,14 +15,15 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync.request; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RequestType.BYTECODES; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; import static org.slf4j.LoggerFactory.getLogger; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncConfiguration; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncProcessState; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapWorldDownloadState; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.stream.Stream; @@ -51,18 +52,26 @@ protected BytecodeRequest( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { - updater.putCode(Hash.wrap(accountHash), code); + + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putCode(Hash.wrap(accountHash), Hash.wrap(codeHash), code); + }, + onForest -> { + onForest.putCode(codeHash, code); + }); downloadState.getMetricsManager().notifyCodeDownloaded(); return possibleParent .map( trieNodeDataRequest -> trieNodeDataRequest.saveParent( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, @@ -79,7 +88,7 @@ public boolean isResponseReceived() { @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { return Stream.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/SnapDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/SnapDataRequest.java index 76d2d9fe596..f3fc1f933d7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/SnapDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/SnapDataRequest.java @@ -27,7 +27,8 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageTrieNodeHealingRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloaderException; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.TasksPriorityProvider; import java.util.HashSet; @@ -115,18 +116,18 @@ public static BytecodeRequest createBytecodeRequest( } public int persist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { return doPersist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + worldStateStorageCoordinator, updater, downloadState, snapSyncState, snapSyncConfiguration); } protected abstract int doPersist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration); @@ -139,7 +140,7 @@ public boolean isExpired(final SnapSyncProcessState snapSyncState) { public abstract Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState); public void registerParent(final TrieNodeHealingRequest parent) { @@ -156,14 +157,18 @@ protected int incrementChildren() { } protected int saveParent( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { if (pendingChildren.decrementAndGet() == 0) { return persist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + worldStateStorageCoordinator, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); } return 0; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java index 9829b4ba90b..751d8e3ac2d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RangeManager.getRangeCount; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RequestType.STORAGE_RANGE; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.StackTrie.FlatDatabaseUpdater.noop; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.eth.sync.snapsync.RangeManager; @@ -32,14 +33,15 @@ import org.hyperledger.besu.ethereum.trie.NodeUpdater; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; @@ -86,8 +88,8 @@ protected StorageRangeDataRequest( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { @@ -96,20 +98,31 @@ protected int doPersist( final AtomicInteger nbNodesSaved = new AtomicInteger(); final NodeUpdater nodeUpdater = (location, hash, value) -> { - updater.putAccountStorageTrieNode(accountHash, location, hash, value); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStorageTrieNode(accountHash, location, hash, value); + }, + onForest -> { + onForest.putAccountStorageTrieNode(hash, value); + }); }; - StackTrie.FlatDatabaseUpdater flatDatabaseUpdater = noop(); - if (worldStateStorage.getFlatDbMode().equals(FlatDbMode.FULL)) { - // we have a flat DB only with Bonsai - flatDatabaseUpdater = - (key, value) -> - ((BonsaiWorldStateKeyValueStorage.Updater) updater) - .putStorageValueBySlotHash( - accountHash, Hash.wrap(key), Bytes32.leftPad(RLP.decodeValue(value))); - } + final AtomicReference flatDatabaseUpdater = + new AtomicReference<>(noop()); + + // we have a flat DB only with Bonsai + worldStateStorageCoordinator.applyOnMatchingFlatMode( + FlatDbMode.FULL, + bonsaiWorldStateStorageStrategy -> { + flatDatabaseUpdater.set( + (key, value) -> + ((BonsaiWorldStateKeyValueStorage.Updater) updater) + .putStorageValueBySlotHash( + accountHash, Hash.wrap(key), Bytes32.leftPad(RLP.decodeValue(value)))); + }); - stackTrie.commit(flatDatabaseUpdater, nodeUpdater); + stackTrie.commit(flatDatabaseUpdater.get(), nodeUpdater); downloadState.getMetricsManager().notifySlotsDownloaded(stackTrie.getElementsCount().get()); @@ -153,7 +166,7 @@ public boolean isExpired(final SnapSyncProcessState snapSyncState) { @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { final List childRequests = new ArrayList<>(); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java index 526a0e9c58b..05bbeed3da5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java @@ -34,7 +34,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.math.BigInteger; import java.util.ArrayList; @@ -75,7 +76,7 @@ public AccountFlatDatabaseHealingRangeRequest( @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { final List childRequests = new ArrayList<>(); if (!existingAccounts.isEmpty()) { @@ -144,8 +145,8 @@ public void addLocalData( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration syncConfig) { @@ -157,7 +158,7 @@ protected int doPersist( final MerkleTrie accountTrie = new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + worldStateStorageCoordinator::getAccountStateTrieNode, getRootHash(), Function.identity(), Function.identity()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java index 56598c91190..e2f3353f20e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountTrieNodeHealingRequest.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal; import static org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest.createAccountTrieNodeDataRequest; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncConfiguration; @@ -24,11 +25,10 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.trie.CompactEncoding; import org.hyperledger.besu.ethereum.trie.MerkleTrie; -import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.ArrayList; import java.util.HashSet; @@ -56,22 +56,29 @@ public AccountTrieNodeHealingRequest( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { if (isRoot()) { downloadState.setRootNodeData(data); } - updater.putAccountStateTrieNode(getLocation(), getNodeHash(), data); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStateTrieNode(getLocation(), getNodeHash(), data); + }, + onForest -> { + onForest.putAccountStateTrieNode(getNodeHash(), data); + }); return 1; } @Override public Optional getExistingData( - final SnapWorldDownloadState downloadState, final WorldStateStorage worldStateStorage) { - return worldStateStorage + final WorldStateStorageCoordinator worldStateStorageCoordinator) { + return worldStateStorageCoordinator .getAccountStateTrieNode(getLocation(), getNodeHash()) .filter(data -> !getLocation().isEmpty()); } @@ -93,11 +100,12 @@ private HashSet getSubLocation(final Bytes location) { } @Override - public Stream getRootStorageRequests(final WorldStateStorage worldStateStorage) { + public Stream getRootStorageRequests( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { final List requests = new ArrayList<>(); final StoredMerklePatriciaTrie accountTrie = new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, + worldStateStorageCoordinator::getAccountStateTrieNode, Hash.hash(data), getLocation(), Function.identity(), @@ -137,7 +145,7 @@ public Stream getRootStorageRequests(final WorldStateStorage wo @Override protected Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, @@ -151,11 +159,10 @@ protected Stream getRequestsFromTrieNodeValue( Bytes32.wrap(CompactEncoding.pathToBytes(Bytes.concatenate(getLocation(), path)))); // update the flat db only for bonsai - if (!worldStateStorage.getFlatDbMode().equals(FlatDbMode.NO_FLATTENED)) { - ((BonsaiWorldStateKeyValueStorage.Updater) worldStateStorage.updater()) - .putAccountInfoState(accountHash, value) - .commit(); - } + worldStateStorageCoordinator.applyWhenFlatModeEnabled( + onBonsai -> { + onBonsai.updater().putAccountInfoState(accountHash, value).commit(); + }); // Add code, if appropriate if (!accountValue.getCodeHash().equals(Hash.EMPTY)) { @@ -164,7 +171,7 @@ protected Stream getRequestsFromTrieNodeValue( // Retrieve the storage root from the database, if available final Hash storageRootFoundInDb = - worldStateStorage + worldStateStorageCoordinator .getTrieNodeUnsafe(Bytes.concatenate(accountHash, Bytes.EMPTY)) .map(Hash::hash) .orElse(Hash.wrap(MerkleTrie.EMPTY_TRIE_NODE_HASH)); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java index ccc3f4453ec..ac554439e91 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java @@ -29,7 +29,8 @@ import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.math.BigInteger; import java.util.ArrayList; @@ -75,7 +76,7 @@ public StorageFlatDatabaseHealingRangeRequest( @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { final List childRequests = new ArrayList<>(); if (!slots.isEmpty()) { @@ -132,8 +133,8 @@ public void addLocalData( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { @@ -147,7 +148,8 @@ protected int doPersist( final MerkleTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateStorageCoordinator.getAccountStorageTrieNode( + accountHash, location, hash), storageRoot, Function.identity(), Function.identity()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java index e6650072a29..d1cea17684a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequest.java @@ -14,16 +14,16 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal; +import static org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator.applyForStrategy; + import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncConfiguration; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapSyncProcessState; import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapWorldDownloadState; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.trie.CompactEncoding; -import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import java.util.List; import java.util.Optional; @@ -46,19 +46,26 @@ public StorageTrieNodeHealingRequest( @Override protected int doPersist( - final WorldStateStorage worldStateStorage, - final Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { - updater.putAccountStorageTrieNode(getAccountHash(), getLocation(), getNodeHash(), data); + applyForStrategy( + updater, + onBonsai -> { + onBonsai.putAccountStorageTrieNode(getAccountHash(), getLocation(), getNodeHash(), data); + }, + onForest -> { + onForest.putAccountStorageTrieNode(getNodeHash(), data); + }); return 1; } @Override public Optional getExistingData( - final SnapWorldDownloadState downloadState, final WorldStateStorage worldStateStorage) { - return worldStateStorage.getAccountStorageTrieNode( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { + return worldStateStorageCoordinator.getAccountStorageTrieNode( getAccountHash(), getLocation(), getNodeHash()); } @@ -70,17 +77,19 @@ protected SnapDataRequest createChildNodeDataRequest(final Hash childHash, final @Override protected Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, final Bytes value) { - if (!worldStateStorage.getFlatDbMode().equals(FlatDbMode.NO_FLATTENED)) { - ((BonsaiWorldStateKeyValueStorage.Updater) worldStateStorage.updater()) - .putStorageValueBySlotHash( - accountHash, getSlotHash(location, path), Bytes32.leftPad(RLP.decodeValue(value))) - .commit(); - } + worldStateStorageCoordinator.applyWhenFlatModeEnabled( + onBonsai -> { + onBonsai + .updater() + .putStorageValueBySlotHash( + accountHash, getSlotHash(location, path), Bytes32.leftPad(RLP.decodeValue(value))) + .commit(); + }); return Stream.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java index ef7191a0167..e114ebb426a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java @@ -24,7 +24,8 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.trie.Node; import org.hyperledger.besu.ethereum.trie.patricia.TrieNodeDecoder; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.TasksPriorityProvider; import java.util.ArrayList; @@ -54,8 +55,8 @@ protected TrieNodeHealingRequest(final Hash nodeHash, final Hash rootHash, final @Override public int persist( - final WorldStateStorage worldStateStorage, - final WorldStateStorage.Updater updater, + final WorldStateStorageCoordinator worldStateStorageCoordinator, + final WorldStateKeyValueStorage.Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncProcessState snapSyncState, final SnapSyncConfiguration snapSyncConfiguration) { @@ -68,13 +69,21 @@ public int persist( checkNotNull(data, "Must set data before node can be persisted."); saved = doPersist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + worldStateStorageCoordinator, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); } if (possibleParent.isPresent()) { return possibleParent .get() .saveParent( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration) + worldStateStorageCoordinator, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration) + saved; } return saved; @@ -83,7 +92,7 @@ public int persist( @Override public Stream getChildRequests( final SnapWorldDownloadState downloadState, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapSyncProcessState snapSyncState) { if (!isResponseReceived()) { // If this node hasn't been downloaded yet, we can't return any child data @@ -103,7 +112,7 @@ public Stream getChildRequests( .map( value -> getRequestsFromTrieNodeValue( - worldStateStorage, + worldStateStorageCoordinator, downloadState, node.getLocation().orElse(Bytes.EMPTY), node.getPath(), @@ -172,19 +181,20 @@ private boolean nodeIsHashReferencedDescendant(final Node node) { } public abstract Optional getExistingData( - final SnapWorldDownloadState downloadState, final WorldStateStorage worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator); public abstract List getTrieNodePath(); protected abstract SnapDataRequest createChildNodeDataRequest( final Hash childHash, final Bytes location); - public Stream getRootStorageRequests(final WorldStateStorage worldStateStorage) { + public Stream getRootStorageRequests( + final WorldStateStorageCoordinator worldStateStorageCoordinator) { return Stream.empty(); } protected abstract Stream getRequestsFromTrieNodeValue( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final SnapWorldDownloadState downloadState, final Bytes location, final Bytes path, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldDownloadState.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldDownloadState.java index 8f53921f4dd..fd3ae682da9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldDownloadState.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/worldstate/WorldDownloadState.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.InMemoryTasksPriorityQueues; import org.hyperledger.besu.services.tasks.Task; import org.hyperledger.besu.services.tasks.TasksPriorityProvider; @@ -53,16 +53,16 @@ public abstract class WorldDownloadState private volatile long timestampOfLastProgress; protected Bytes rootNodeData; - protected final WorldStateStorage worldStateStorage; + protected final WorldStateStorageCoordinator worldStateStorageCoordinator; protected WorldStateDownloadProcess worldStateDownloadProcess; public WorldDownloadState( - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final InMemoryTasksPriorityQueues pendingRequests, final int maxRequestsWithoutProgress, final long minMillisBeforeStalling, final Clock clock) { - this.worldStateStorage = worldStateStorage; + this.worldStateStorageCoordinator = worldStateStorageCoordinator; this.minMillisBeforeStalling = minMillisBeforeStalling; this.timestampOfLastProgress = clock.millis(); this.downloadWasResumed = !pendingRequests.isEmpty(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index 19b738d7c4d..822ac5095d4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -36,7 +36,10 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -53,8 +56,6 @@ public class CheckPointSyncChainDownloaderTest { - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); - protected ProtocolSchedule protocolSchedule; protected EthProtocolManager ethProtocolManager; protected EthContext ethContext; @@ -66,6 +67,8 @@ public class CheckPointSyncChainDownloaderTest { protected Blockchain otherBlockchain; private Checkpoint checkpoint; + private WorldStateStorageCoordinator worldStateStorageCoordinator; + static class CheckPointSyncChainDownloaderTestArguments implements ArgumentsProvider { @Override public Stream provideArguments(final ExtensionContext context) { @@ -74,11 +77,26 @@ public Stream provideArguments(final ExtensionContext conte } } - public void setup(final DataStorageFormat storageFormat) { - when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); - final BlockchainSetupUtil localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); + public void setup(final DataStorageFormat dataStorageFormat) { + final WorldStateKeyValueStorage worldStateKeyValueStorage; + if (dataStorageFormat.equals(DataStorageFormat.BONSAI)) { + worldStateKeyValueStorage = mock(BonsaiWorldStateKeyValueStorage.class); + when(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage) + .isWorldStateAvailable(any(), any())) + .thenReturn(true); + } else { + worldStateKeyValueStorage = mock(ForestWorldStateKeyValueStorage.class); + when(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage) + .isWorldStateAvailable(any())) + .thenReturn(true); + } + when(worldStateKeyValueStorage.getDataStorageFormat()).thenReturn(dataStorageFormat); + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + + final BlockchainSetupUtil localBlockchainSetup = + BlockchainSetupUtil.forTesting(dataStorageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); - otherBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); + otherBlockchainSetup = BlockchainSetupUtil.forTesting(dataStorageFormat); otherBlockchain = otherBlockchainSetup.getBlockchain(); protocolSchedule = localBlockchainSetup.getProtocolSchedule(); protocolContext = localBlockchainSetup.getProtocolContext(); @@ -114,7 +132,7 @@ private ChainDownloader downloader( final SynchronizerConfiguration syncConfig, final long pivotBlockNumber) { return CheckpointSyncChainDownloader.create( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java index 1cb6521e00e..765eac4c5c7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java @@ -31,8 +31,12 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.FastDownloaderFactory; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import java.io.File; import java.io.IOException; @@ -40,10 +44,16 @@ import java.nio.file.Path; import java.time.Clock; import java.util.Optional; +import java.util.stream.Stream; import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @@ -59,15 +69,36 @@ public class FastDownloaderFactoryTest { @Mock private ProtocolContext protocolContext; @Mock private MetricsSystem metricsSystem; @Mock private EthContext ethContext; - @Mock private WorldStateStorage worldStateStorage; @Mock private SyncState syncState; @Mock private Clock clock; @Mock private Path dataDirectory; @Mock private PivotBlockSelector pivotBlockSelector; + private WorldStateKeyValueStorage worldStateKeyValueStorage; + private WorldStateStorageCoordinator worldStateStorageCoordinator; - @SuppressWarnings("unchecked") - @Test - public void shouldThrowIfSyncModeChangedWhileFastSyncIncomplete() { + static class FastDownloaderFactoryTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } + } + + public void setup(final DataStorageFormat dataStorageFormat) { + if (dataStorageFormat.equals(DataStorageFormat.BONSAI)) { + worldStateKeyValueStorage = mock(BonsaiWorldStateKeyValueStorage.class); + } else { + worldStateKeyValueStorage = mock(ForestWorldStateKeyValueStorage.class); + } + when(worldStateKeyValueStorage.getDataStorageFormat()).thenReturn(dataStorageFormat); + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + } + + @ParameterizedTest + @ArgumentsSource(FastDownloaderFactoryTestArguments.class) + public void shouldThrowIfSyncModeChangedWhileFastSyncIncomplete( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); initDataDirectory(true); when(syncConfig.getSyncMode()).thenReturn(SyncMode.FULL); @@ -81,15 +112,18 @@ public void shouldThrowIfSyncModeChangedWhileFastSyncIncomplete() { protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock)) .isInstanceOf(IllegalStateException.class); } @SuppressWarnings({"unchecked", "rawtypes"}) - @Test - public void shouldNotThrowIfSyncModeChangedWhileFastSyncComplete() { + @ParameterizedTest + @ArgumentsSource(FastDownloaderFactoryTestArguments.class) + public void shouldNotThrowIfSyncModeChangedWhileFastSyncComplete( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); initDataDirectory(false); when(syncConfig.getSyncMode()).thenReturn(SyncMode.FULL); @@ -102,15 +136,18 @@ public void shouldNotThrowIfSyncModeChangedWhileFastSyncComplete() { protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); assertThat(result).isEmpty(); } @SuppressWarnings("unchecked") - @Test - public void shouldNotThrowWhenFastSyncModeRequested() throws NoSuchFieldException { + @ParameterizedTest + @ArgumentsSource(FastDownloaderFactoryTestArguments.class) + public void shouldNotThrowWhenFastSyncModeRequested(final DataStorageFormat dataStorageFormat) + throws NoSuchFieldException { + setup(dataStorageFormat); initDataDirectory(false); final MutableBlockchain mutableBlockchain = mock(MutableBlockchain.class); @@ -126,15 +163,19 @@ public void shouldNotThrowWhenFastSyncModeRequested() throws NoSuchFieldExceptio protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); verify(mutableBlockchain).getChainHeadBlockNumber(); } - @Test - public void shouldClearWorldStateDuringFastSyncWhenStateQueDirectoryExists() throws IOException { + @ParameterizedTest + @ArgumentsSource(FastDownloaderFactoryTestArguments.class) + public void shouldClearWorldStateDuringFastSyncWhenStateQueDirectoryExists( + final DataStorageFormat dataStorageFormat) throws IOException { + Assumptions.assumeTrue(dataStorageFormat == DataStorageFormat.FOREST); + setup(dataStorageFormat); when(syncConfig.getSyncMode()).thenReturn(SyncMode.FAST); final MutableBlockchain mutableBlockchain = mock(MutableBlockchain.class); when(mutableBlockchain.getChainHeadBlockNumber()).thenReturn(0L); @@ -156,16 +197,20 @@ public void shouldClearWorldStateDuringFastSyncWhenStateQueDirectoryExists() thr protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock); - verify(worldStateStorage).clear(); + verify(worldStateKeyValueStorage).clear(); assertThat(Files.exists(stateQueueDir)).isFalse(); } - @Test - public void shouldCrashWhenStateQueueIsNotDirectory() throws IOException { + @ParameterizedTest + @ArgumentsSource(FastDownloaderFactoryTestArguments.class) + public void shouldCrashWhenStateQueueIsNotDirectory(final DataStorageFormat dataStorageFormat) + throws IOException { + Assumptions.assumeTrue(dataStorageFormat == DataStorageFormat.FOREST); + setup(dataStorageFormat); when(syncConfig.getSyncMode()).thenReturn(SyncMode.FAST); final MutableBlockchain mutableBlockchain = mock(MutableBlockchain.class); when(mutableBlockchain.getChainHeadBlockNumber()).thenReturn(0L); @@ -188,7 +233,7 @@ public void shouldCrashWhenStateQueueIsNotDirectory() throws IOException { protocolContext, metricsSystem, ethContext, - worldStateStorage, + worldStateStorageCoordinator, syncState, clock)) .isInstanceOf(IllegalStateException.class); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java index 9813dc132fe..e060bab6fbe 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java @@ -40,7 +40,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -64,7 +64,8 @@ public class FastSyncActionsTest { private final SynchronizerConfiguration.Builder syncConfigBuilder = new SynchronizerConfiguration.Builder().syncMode(SyncMode.FAST).fastSyncPivotDistance(1000); - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + mock(WorldStateStorageCoordinator.class); private final AtomicInteger timeoutCount = new AtomicInteger(0); private SynchronizerConfiguration syncConfig = syncConfigBuilder.build(); private FastSyncActions fastSyncActions; @@ -85,6 +86,7 @@ public Stream provideArguments(final ExtensionContext conte } public void setUp(final DataStorageFormat storageFormat) { + when(worldStateStorageCoordinator.getDataStorageFormat()).thenReturn(storageFormat); blockchainSetupUtil = BlockchainSetupUtil.forTesting(storageFormat); blockchainSetupUtil.importAllBlocks(); blockchain = blockchainSetupUtil.getBlockchain(); @@ -529,7 +531,7 @@ private FastSyncActions createFastSyncActions( final EthContext ethContext = ethProtocolManager.ethContext(); return new FastSyncActions( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java index 9312ca832eb..a731185167a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java @@ -35,7 +35,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; @@ -52,7 +52,8 @@ public class FastSyncChainDownloaderTest { - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + mock(WorldStateStorageCoordinator.class); protected ProtocolSchedule protocolSchedule; protected EthProtocolManager ethProtocolManager; @@ -73,7 +74,8 @@ public Stream provideArguments(final ExtensionContext conte } public void setup(final DataStorageFormat storageFormat) { - when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); + when(worldStateStorageCoordinator.getDataStorageFormat()).thenReturn(storageFormat); + when(worldStateStorageCoordinator.isWorldStateAvailable(any(), any())).thenReturn(true); final BlockchainSetupUtil localBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); localBlockchain = localBlockchainSetup.getBlockchain(); otherBlockchainSetup = BlockchainSetupUtil.forTesting(storageFormat); @@ -100,7 +102,7 @@ private ChainDownloader downloader( final SynchronizerConfiguration syncConfig, final long pivotBlockNumber) { return FastSyncChainDownloader.create( syncConfig, - worldStateStorage, + worldStateStorageCoordinator, protocolSchedule, protocolContext, ethContext, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java index e8eadea3ade..0c625c61344 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java @@ -34,7 +34,10 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.NodeDataRequest; import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.tasks.TaskCollection; @@ -44,18 +47,20 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.stream.Stream; import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; public class FastSyncDownloaderTest { @SuppressWarnings("unchecked") private final FastSyncActions fastSyncActions = mock(FastSyncActions.class); - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); - private final WorldStateDownloader worldStateDownloader = mock(FastWorldStateDownloader.class); private final FastSyncStateStorage storage = mock(FastSyncStateStorage.class); @@ -65,25 +70,47 @@ public class FastSyncDownloaderTest { private final ChainDownloader chainDownloader = mock(ChainDownloader.class); private final Path fastSyncDataDirectory = null; + private WorldStateStorageCoordinator worldStateStorageCoordinator; + private FastSyncDownloader downloader; + + static class FastSyncDownloaderTestArguments implements ArgumentsProvider { + @Override + public Stream provideArguments(final ExtensionContext context) { + return Stream.of( + Arguments.of(DataStorageFormat.BONSAI), Arguments.of(DataStorageFormat.FOREST)); + } + } - private final FastSyncDownloader downloader = - new FastSyncDownloader<>( - fastSyncActions, - worldStateStorage, - worldStateDownloader, - storage, - taskCollection, - fastSyncDataDirectory, - FastSyncState.EMPTY_SYNC_STATE); - - @BeforeEach - public void setup() { - when(worldStateStorage.getDataStorageFormat()).thenReturn(DataStorageFormat.FOREST); - when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true); + public void setup(final DataStorageFormat dataStorageFormat) { + final WorldStateKeyValueStorage worldStateKeyValueStorage; + if (dataStorageFormat.equals(DataStorageFormat.BONSAI)) { + worldStateKeyValueStorage = mock(BonsaiWorldStateKeyValueStorage.class); + when(((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage) + .isWorldStateAvailable(any(), any())) + .thenReturn(true); + } else { + worldStateKeyValueStorage = mock(ForestWorldStateKeyValueStorage.class); + when(((ForestWorldStateKeyValueStorage) worldStateKeyValueStorage) + .isWorldStateAvailable(any())) + .thenReturn(true); + } + when(worldStateKeyValueStorage.getDataStorageFormat()).thenReturn(dataStorageFormat); + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + downloader = + new FastSyncDownloader<>( + fastSyncActions, + worldStateStorageCoordinator, + worldStateDownloader, + storage, + taskCollection, + fastSyncDataDirectory, + FastSyncState.EMPTY_SYNC_STATE); } - @Test - public void shouldCompleteFastSyncSuccessfully() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldCompleteFastSyncSuccessfully(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final FastSyncState selectPivotBlockState = new FastSyncState(50); final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader(); final FastSyncState downloadPivotBlockHeaderState = new FastSyncState(pivotBlockHeader); @@ -111,8 +138,10 @@ public void shouldCompleteFastSyncSuccessfully() { assertThat(result).isCompletedWithValue(downloadPivotBlockHeaderState); } - @Test - public void shouldResumeFastSync() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldResumeFastSync(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader(); final FastSyncState fastSyncState = new FastSyncState(pivotBlockHeader); final CompletableFuture complete = completedFuture(fastSyncState); @@ -127,7 +156,7 @@ public void shouldResumeFastSync() { final FastSyncDownloader resumedDownloader = new FastSyncDownloader<>( fastSyncActions, - worldStateStorage, + worldStateStorageCoordinator, worldStateDownloader, storage, taskCollection, @@ -147,8 +176,10 @@ public void shouldResumeFastSync() { assertThat(result).isCompletedWithValue(fastSyncState); } - @Test - public void shouldAbortIfSelectPivotBlockFails() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldAbortIfSelectPivotBlockFails(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); when(fastSyncActions.selectPivotBlock(FastSyncState.EMPTY_SYNC_STATE)) .thenThrow(new SyncException(SyncError.UNEXPECTED_ERROR)); @@ -160,8 +191,10 @@ public void shouldAbortIfSelectPivotBlockFails() { verifyNoMoreInteractions(fastSyncActions); } - @Test - public void shouldAbortIfWorldStateDownloadFails() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldAbortIfWorldStateDownloadFails(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture worldStateFuture = new CompletableFuture<>(); final CompletableFuture chainFuture = new CompletableFuture<>(); final FastSyncState selectPivotBlockState = new FastSyncState(50); @@ -198,8 +231,10 @@ public void shouldAbortIfWorldStateDownloadFails() { assertThat(chainFuture).isCancelled(); } - @Test - public void shouldAbortIfChainDownloadFails() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldAbortIfChainDownloadFails(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture chainFuture = new CompletableFuture<>(); final CompletableFuture worldStateFuture = new CompletableFuture<>(); final FastSyncState selectPivotBlockState = new FastSyncState(50); @@ -234,8 +269,10 @@ public void shouldAbortIfChainDownloadFails() { assertThat(worldStateFuture).isCancelled(); } - @Test - public void shouldAbortIfStopped() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldAbortIfStopped(final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final FastSyncState selectPivotBlockState = new FastSyncState(50); final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader(); final FastSyncState downloadPivotBlockHeaderState = new FastSyncState(pivotBlockHeader); @@ -268,8 +305,11 @@ public void shouldAbortIfStopped() { verifyNoMoreInteractions(fastSyncActions, worldStateDownloader, storage); } - @Test - public void shouldNotConsiderFastSyncCompleteIfOnlyWorldStateDownloadIsComplete() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldNotConsiderFastSyncCompleteIfOnlyWorldStateDownloadIsComplete( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture chainFuture = new CompletableFuture<>(); final CompletableFuture worldStateFuture = new CompletableFuture<>(); final FastSyncState selectPivotBlockState = new FastSyncState(50); @@ -303,8 +343,11 @@ public void shouldNotConsiderFastSyncCompleteIfOnlyWorldStateDownloadIsComplete( assertThat(result).isNotDone(); } - @Test - public void shouldNotConsiderFastSyncCompleteIfOnlyChainDownloadIsComplete() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldNotConsiderFastSyncCompleteIfOnlyChainDownloadIsComplete( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture chainFuture = new CompletableFuture<>(); final CompletableFuture worldStateFuture = new CompletableFuture<>(); final FastSyncState selectPivotBlockState = new FastSyncState(50); @@ -339,8 +382,11 @@ public void shouldNotConsiderFastSyncCompleteIfOnlyChainDownloadIsComplete() { } @SuppressWarnings("unchecked") - @Test - public void shouldResetFastSyncStateAndRestartProcessIfWorldStateIsUnavailable() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldResetFastSyncStateAndRestartProcessIfWorldStateIsUnavailable( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture firstWorldStateFuture = new CompletableFuture<>(); final CompletableFuture secondWorldStateFuture = new CompletableFuture<>(); final CompletableFuture chainFuture = new CompletableFuture<>(); @@ -410,8 +456,11 @@ public void shouldResetFastSyncStateAndRestartProcessIfWorldStateIsUnavailable() } @SuppressWarnings("unchecked") - @Test - public void shouldResetFastSyncStateAndRestartProcessIfANonFastSyncExceptionOccurs() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldResetFastSyncStateAndRestartProcessIfANonFastSyncExceptionOccurs( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final CompletableFuture firstWorldStateFuture = new CompletableFuture<>(); final CompletableFuture secondWorldStateFuture = new CompletableFuture<>(); final CompletableFuture chainFuture = new CompletableFuture<>(); @@ -484,14 +533,20 @@ public void shouldResetFastSyncStateAndRestartProcessIfANonFastSyncExceptionOccu assertThat(result).isCompletedWithValue(secondDownloadPivotBlockHeaderState); } - @Test - public void shouldNotHaveTrailingPeerRequirementsBeforePivotBlockSelected() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldNotHaveTrailingPeerRequirementsBeforePivotBlockSelected( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); downloader.start(); Assertions.assertThat(downloader.calculateTrailingPeerRequirements()).isEmpty(); } - @Test - public void shouldNotAllowPeersBeforePivotBlockOnceSelected() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldNotAllowPeersBeforePivotBlockOnceSelected( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final FastSyncState selectPivotBlockState = new FastSyncState(50); final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader(); final FastSyncState downloadPivotBlockHeaderState = new FastSyncState(pivotBlockHeader); @@ -512,8 +567,11 @@ public void shouldNotAllowPeersBeforePivotBlockOnceSelected() { .contains(new TrailingPeerRequirements(50, 0)); } - @Test - public void shouldNotHaveTrailingPeerRequirementsAfterDownloadCompletes() { + @ParameterizedTest + @ArgumentsSource(FastSyncDownloaderTestArguments.class) + public void shouldNotHaveTrailingPeerRequirementsAfterDownloadCompletes( + final DataStorageFormat dataStorageFormat) { + setup(dataStorageFormat); final FastSyncState selectPivotBlockState = new FastSyncState(50); final BlockHeader pivotBlockHeader = new BlockHeaderTestFixture().number(50).buildHeader(); final FastSyncState downloadPivotBlockHeaderState = new FastSyncState(pivotBlockHeader); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java index 04b3d7136ce..3555a9b7179 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java @@ -29,7 +29,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -55,7 +56,9 @@ public class FastWorldDownloadStateTest { private static final int MAX_REQUESTS_WITHOUT_PROGRESS = 10; private static final long MIN_MILLIS_BEFORE_STALLING = 50_000; - private WorldStateStorage worldStateStorage; + private WorldStateKeyValueStorage worldStateKeyValueStorage; + + private WorldStateStorageCoordinator worldStateStorageCoordinator; private final BlockHeader header = new BlockHeaderTestFixture().stateRoot(ROOT_NODE_HASH).buildHeader(); @@ -79,17 +82,20 @@ public Stream provideArguments(final ExtensionContext conte public void setUp(final DataStorageFormat storageFormat) { if (storageFormat == DataStorageFormat.BONSAI) { - worldStateStorage = + worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( new InMemoryKeyValueStorageProvider(), new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); } else { - worldStateStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + worldStateKeyValueStorage = + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); } + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + downloadState = new FastWorldDownloadState( - worldStateStorage, + worldStateStorageCoordinator, pendingRequests, MAX_REQUESTS_WITHOUT_PROGRESS, MIN_MILLIS_BEFORE_STALLING, @@ -118,7 +124,9 @@ public void shouldStoreRootNodeBeforeReturnedFutureCompletes( final CompletableFuture postFutureChecks = future.thenAccept( result -> - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + assertThat( + worldStateStorageCoordinator.getAccountStateTrieNode( + Bytes.EMPTY, ROOT_NODE_HASH)) .contains(ROOT_NODE_DATA)); downloadState.checkCompletion(header); @@ -137,7 +145,8 @@ public void shouldNotCompleteWhenThereArePendingTasks(final DataStorageFormat st downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java index 8fbe881cfaa..938cf020af5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldStateDownloaderTest.java @@ -57,9 +57,9 @@ import org.hyperledger.besu.ethereum.trie.patricia.TrieNodeDecoder; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.internal.EvmConfiguration; @@ -178,7 +178,7 @@ void downloadEmptyWorldState() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateDownloader downloader = createDownloader(ethProtocolManager.ethContext(), localStorage, taskCollection); @@ -263,7 +263,7 @@ void canRecoverFromTimeouts() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateDownloader downloader = createDownloader(ethProtocolManager.ethContext(), localStorage, taskCollection); @@ -283,7 +283,9 @@ void canRecoverFromTimeouts() { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); @@ -318,14 +320,14 @@ void doesNotRequestKnownCodeFromNetwork() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); // Seed local storage with some contract values final Map knownCode = new HashMap<>(); accounts.subList(0, 5).forEach(a -> knownCode.put(a.getCodeHash(), a.getCode())); - final Updater localStorageUpdater = localStorage.updater(); - knownCode.forEach((bytes32, code) -> localStorageUpdater.putCode(null, code)); + final ForestWorldStateKeyValueStorage.Updater localStorageUpdater = localStorage.updater(); + knownCode.forEach((bytes32, code) -> localStorageUpdater.putCode(code)); localStorageUpdater.commit(); final WorldStateDownloader downloader = @@ -357,7 +359,9 @@ void doesNotRequestKnownCodeFromNetwork() { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); @@ -403,7 +407,7 @@ private void testCancellation(final boolean shouldCancelFuture) { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateDownloader downloader = @@ -449,19 +453,20 @@ private void testCancellation(final boolean shouldCancelFuture) { verify(taskCollection, never()).remove(); verify(taskCollection, never()).add(any(NodeDataRequest.class)); // Target world state should not be available - assertThat(localStorage.isWorldStateAvailable(header.getStateRoot(), header.getHash())) - .isFalse(); + assertThat(localStorage.isWorldStateAvailable(header.getStateRoot())).isFalse(); } @Test @Timeout(value = 60) void doesNotRequestKnownAccountTrieNodesFromNetwork() { // Setup "remote" state - final WorldStateStorage remoteStorage = + final ForestWorldStateKeyValueStorage remoteStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive remoteWorldStateArchive = new ForestWorldStateArchive( - remoteStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(remoteStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable(); // Generate accounts and save corresponding state root @@ -480,7 +485,7 @@ void doesNotRequestKnownAccountTrieNodesFromNetwork() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); // Seed local storage with some trie node values @@ -489,12 +494,12 @@ void doesNotRequestKnownAccountTrieNodesFromNetwork() { final Set knownNodes = new HashSet<>(); final Set unknownNodes = new HashSet<>(); assertThat(allNodes).isNotEmpty(); // Sanity check - final Updater localStorageUpdater = localStorage.updater(); + final ForestWorldStateKeyValueStorage.Updater localStorageUpdater = localStorage.updater(); final AtomicBoolean storeNode = new AtomicBoolean(true); allNodes.forEach( (nodeHash, node) -> { if (storeNode.get()) { - localStorageUpdater.putAccountStateTrieNode(null, nodeHash, node); + localStorageUpdater.putAccountStateTrieNode(nodeHash, node); knownNodes.add(nodeHash); } else { unknownNodes.add(nodeHash); @@ -534,7 +539,9 @@ void doesNotRequestKnownAccountTrieNodesFromNetwork() { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); @@ -544,11 +551,13 @@ void doesNotRequestKnownAccountTrieNodesFromNetwork() { @Timeout(value = 60) void doesNotRequestKnownStorageTrieNodesFromNetwork() { // Setup "remote" state - final WorldStateStorage remoteStorage = + final ForestWorldStateKeyValueStorage remoteStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive remoteWorldStateArchive = new ForestWorldStateArchive( - remoteStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(remoteStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable(); // Generate accounts and save corresponding state root @@ -567,13 +576,13 @@ void doesNotRequestKnownStorageTrieNodesFromNetwork() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); // Seed local storage with some trie node values final List storageRootHashes = new StoredMerklePatriciaTrie<>( - remoteStorage::getNodeData, + (location, hash) -> remoteStorage.getNodeData(hash), remoteWorldState.rootHash(), Function.identity(), Function.identity()) @@ -590,13 +599,13 @@ void doesNotRequestKnownStorageTrieNodesFromNetwork() { collectTrieNodesToBeRequestedAfterRoot(remoteStorage, storageRootHash, 5)); } assertThat(allTrieNodes).isNotEmpty(); // Sanity check - final Updater localStorageUpdater = localStorage.updater(); + final ForestWorldStateKeyValueStorage.Updater localStorageUpdater = localStorage.updater(); boolean storeNode = true; for (final Map.Entry entry : allTrieNodes.entrySet()) { final Bytes32 hash = entry.getKey(); final Bytes data = entry.getValue(); if (storeNode) { - localStorageUpdater.putAccountStorageTrieNode(null, null, hash, data); + localStorageUpdater.putAccountStorageTrieNode(hash, data); knownNodes.add(hash); } else { unknownNodes.add(hash); @@ -622,7 +631,7 @@ void doesNotRequestKnownStorageTrieNodesFromNetwork() { respondUntilDone(peers, responder, result); // World state should be available by the time the result is complete - assertThat(localStorage.isWorldStateAvailable(stateRoot, header.getHash())).isTrue(); + assertThat(localStorage.isWorldStateAvailable(stateRoot)).isTrue(); // Check that unknown trie nodes were requested final List requestedHashes = @@ -639,7 +648,9 @@ void doesNotRequestKnownStorageTrieNodesFromNetwork() { // Check that all expected account data was downloaded final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertThat(result).isDone(); assertAccountsMatch(localWorldState, accounts); @@ -652,11 +663,13 @@ void stalledDownloader() { EthProtocolManagerTestUtil.create(new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem())); // Setup "remote" state - final WorldStateStorage remoteStorage = + final ForestWorldStateKeyValueStorage remoteStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive remoteWorldStateArchive = new ForestWorldStateArchive( - remoteStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(remoteStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable(); // Generate accounts and save corresponding state root @@ -668,7 +681,7 @@ void stalledDownloader() { final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder().worldStateMaxRequestsWithoutProgress(10).build(); @@ -714,11 +727,13 @@ void stalledDownloader() { @Timeout(value = 60) void resumesFromNonEmptyQueue() { // Setup "remote" state - final WorldStateStorage remoteStorage = + final ForestWorldStateKeyValueStorage remoteStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive remoteWorldStateArchive = new ForestWorldStateArchive( - remoteStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(remoteStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable(); // Generate accounts and save corresponding state root @@ -742,7 +757,7 @@ void resumesFromNonEmptyQueue() { verify(taskCollection, times(1)).add(argThat((r) -> r.getHash().equals(hash))); } - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder().worldStateMaxRequestsWithoutProgress(10).build(); @@ -762,7 +777,7 @@ void resumesFromNonEmptyQueue() { CompletableFuture result = downloader.run(null, new FastSyncState(header)); peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone()); - assertThat(localStorage.isWorldStateAvailable(stateRoot, header.getHash())).isTrue(); + assertThat(localStorage.isWorldStateAvailable(stateRoot)).isTrue(); // Check that already enqueued trie nodes were requested final List requestedHashes = @@ -783,7 +798,9 @@ void resumesFromNonEmptyQueue() { assertThat(result).isDone(); final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get(); assertAccountsMatch(localWorldState, accounts); } @@ -800,10 +817,10 @@ void resumesFromNonEmptyQueue() { * @return A list of hash-node pairs */ private Map collectTrieNodesToBeRequestedAfterRoot( - final WorldStateStorage storage, final Bytes32 rootHash, final int maxNodes) { + final ForestWorldStateKeyValueStorage storage, final Bytes32 rootHash, final int maxNodes) { final Map trieNodes = new HashMap<>(); - TrieNodeDecoder.breadthFirstDecoder(storage::getNodeData, rootHash) + TrieNodeDecoder.breadthFirstDecoder((location, hash) -> storage.getNodeData(hash), rootHash) .filter(n -> !Objects.equals(n.getHash(), rootHash)) .filter(Node::isReferencedByHash) .limit(maxNodes) @@ -823,10 +840,10 @@ private Map collectTrieNodesToBeRequestedAfterRoot( * @return A list of node hashes */ private List getFirstSetOfChildNodeRequests( - final WorldStateStorage storage, final Bytes32 rootHash) { + final ForestWorldStateKeyValueStorage storage, final Bytes32 rootHash) { final List hashesToRequest = new ArrayList<>(); - final Bytes rootNodeRlp = storage.getNodeData(Bytes.EMPTY, rootHash).get(); + final Bytes rootNodeRlp = storage.getNodeData(rootHash).get(); TrieNodeDecoder.decodeNodes(Bytes.EMPTY, rootNodeRlp).stream() .filter(n -> !Objects.equals(n.getHash(), rootHash)) .filter(Node::isReferencedByHash) @@ -853,11 +870,13 @@ private void downloadAvailableWorldStateFromPeers( final int trailingPeerCount = 5; // Setup "remote" state - final WorldStateStorage remoteStorage = + final ForestWorldStateKeyValueStorage remoteStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive remoteWorldStateArchive = new ForestWorldStateArchive( - remoteStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(remoteStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable(); // Generate accounts and save corresponding state root @@ -878,11 +897,13 @@ private void downloadAvailableWorldStateFromPeers( final InMemoryTasksPriorityQueues taskCollection = new InMemoryTasksPriorityQueues<>(); - final WorldStateStorage localStorage = + final ForestWorldStateKeyValueStorage localStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final WorldStateArchive localWorldStateArchive = new ForestWorldStateArchive( - localStorage, createPreimageStorage(), EvmConfiguration.DEFAULT); + new WorldStateStorageCoordinator(localStorage), + createPreimageStorage(), + EvmConfiguration.DEFAULT); final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder() .worldStateHashCountPerRequest(hashesPerRequest) @@ -1010,7 +1031,7 @@ private void assertAccountsMatch( private WorldStateDownloader createDownloader( final EthContext context, - final WorldStateStorage storage, + final WorldStateKeyValueStorage storage, final InMemoryTasksPriorityQueues taskCollection) { return createDownloader( SynchronizerConfiguration.builder().build(), context, storage, taskCollection); @@ -1019,11 +1040,11 @@ private WorldStateDownloader createDownloader( private WorldStateDownloader createDownloader( final SynchronizerConfiguration config, final EthContext context, - final WorldStateStorage storage, + final WorldStateKeyValueStorage storage, final InMemoryTasksPriorityQueues taskCollection) { return new FastWorldStateDownloader( context, - storage, + new WorldStateStorageCoordinator(storage), taskCollection, config.getWorldStateHashCountPerRequest(), config.getWorldStateRequestParallelism(), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java index 625b3f72eaa..e4a827b7f00 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java @@ -22,8 +22,10 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.pipeline.Pipe; import org.hyperledger.besu.services.tasks.Task; @@ -31,6 +33,7 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -38,8 +41,10 @@ public class LoadLocalDataStepTest { private static final Bytes DATA = Bytes.of(1, 2, 3); private static final Hash HASH = Hash.hash(DATA); - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); - private final WorldStateStorage.Updater updater = mock(WorldStateStorage.Updater.class); + private final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = + mock(BonsaiWorldStateKeyValueStorage.class); + private final BonsaiWorldStateKeyValueStorage.Updater updater = + mock(BonsaiWorldStateKeyValueStorage.Updater.class); private final CodeNodeDataRequest request = NodeDataRequest.createCodeRequest(HASH, Optional.empty()); @@ -48,7 +53,13 @@ public class LoadLocalDataStepTest { private final Pipe> completedTasks = new Pipe<>(10, NO_OP_COUNTER, NO_OP_COUNTER, NO_OP_COUNTER); private final LoadLocalDataStep loadLocalDataStep = - new LoadLocalDataStep(worldStateStorage, new NoOpMetricsSystem()); + new LoadLocalDataStep( + new WorldStateStorageCoordinator(worldStateKeyValueStorage), new NoOpMetricsSystem()); + + @BeforeEach + public void setup() { + when(worldStateKeyValueStorage.getDataStorageFormat()).thenReturn(DataStorageFormat.BONSAI); + } @Test public void shouldReturnStreamWithUnchangedTaskWhenDataNotPresent() { @@ -61,8 +72,8 @@ public void shouldReturnStreamWithUnchangedTaskWhenDataNotPresent() { @Test public void shouldReturnEmptyStreamAndSendTaskToCompletedPipeWhenDataIsPresent() { - when(worldStateStorage.getCode(HASH, Hash.EMPTY)).thenReturn(Optional.of(DATA)); - when(worldStateStorage.updater()).thenReturn(updater); + when(worldStateKeyValueStorage.getCode(HASH, Hash.EMPTY)).thenReturn(Optional.of(DATA)); + when(worldStateKeyValueStorage.updater()).thenReturn(updater); final Stream> output = loadLocalDataStep.loadLocalData(task, completedTasks); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java index 367e279a6fa..17a7dc831b3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStepTest.java @@ -23,11 +23,11 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.trie.MerkleTrie; +import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.SimpleMerklePatriciaTrie; -import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.services.tasks.Task; import java.nio.charset.StandardCharsets; @@ -39,16 +39,18 @@ public class PersistDataStepTest { - private final WorldStateStorage worldStateStorage = - new InMemoryKeyValueStorageProvider() - .createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG); + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + private final FastWorldDownloadState downloadState = mock(FastWorldDownloadState.class); private final Bytes rootNodeData = Bytes.of(1, 1, 1, 1); private final BlockHeader blockHeader = new BlockHeaderTestFixture().stateRoot(Hash.hash(rootNodeData)).buildHeader(); - private final PersistDataStep persistDataStep = new PersistDataStep(worldStateStorage); + private final PersistDataStep persistDataStep = new PersistDataStep(worldStateStorageCoordinator); @Test public void shouldPersistDataWhenPresentWithoutChildren() { @@ -76,8 +78,8 @@ public void shouldSkipPersistingTasksWithNoData() { persistDataStep.persist(tasks, blockHeader, downloadState); assertThat(result).isSameAs(tasks); - assertThat(worldStateStorage.contains(withData.getData().getHash())).isTrue(); - assertThat(worldStateStorage.contains(withoutData.getData().getHash())).isFalse(); + assertThat(worldStateKeyValueStorage.contains(withData.getData().getHash())).isTrue(); + assertThat(worldStateKeyValueStorage.contains(withoutData.getData().getHash())).isFalse(); } @Test @@ -88,7 +90,7 @@ public void shouldStoreRootNodeDataInDownloadStateInsteadOfPersisting() { persistDataStep.persist(tasks, blockHeader, downloadState); assertThat(result).isSameAs(tasks); - assertThat(worldStateStorage.contains(rootNode.getData().getHash())).isFalse(); + assertThat(worldStateKeyValueStorage.contains(rootNode.getData().getHash())).isFalse(); verify(downloadState).setRootNodeData(rootNode.getData().getData()); } @@ -120,7 +122,7 @@ private StubTask createTaskWithoutData(final Bytes data) { private void assertDataPersisted(final List> tasks) { tasks.forEach( task -> - assertThat(worldStateStorage.getNodeData(null, task.getData().getHash())) + assertThat(worldStateKeyValueStorage.getNodeData(task.getData().getHash())) .isEqualTo(Optional.of(task.getData().getData()))); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java index cb6f48f364f..28001a2a377 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java @@ -36,7 +36,7 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.List; @@ -57,12 +57,14 @@ public class AccountHealingTrackingTest { private final List
accounts = List.of(Address.fromHexString("0xdeadbeef")); - private final WorldStateStorage worldStateStorage = + private final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( new InMemoryKeyValueStorageProvider(), new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + private WorldStateStorageCoordinator worldStateStorageCoordinator; + private WorldStateProofProvider worldStateProofProvider; private MerkleTrie accountStateTrie; @@ -71,11 +73,12 @@ public class AccountHealingTrackingTest { @BeforeEach public void setup() { + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); accountStateTrie = TrieGenerator.generateTrie( - worldStateStorage, + worldStateStorageCoordinator, accounts.stream().map(Address::addressHash).collect(Collectors.toList())); - worldStateProofProvider = new WorldStateProofProvider(worldStateStorage); + worldStateProofProvider = new WorldStateProofProvider(worldStateStorageCoordinator); } @Test @@ -90,7 +93,8 @@ void avoidMarkingAccountWhenStorageProofValid() { new StoredMerklePatriciaTrie<>( new StoredNodeFactory<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode( + accountHash, location, hash), Function.identity(), Function.identity()), stateTrieAccountValue.getStorageRoot()); @@ -121,7 +125,8 @@ void avoidMarkingAccountWhenStorageProofValid() { MAX_RANGE); storageRangeDataRequest.addResponse( snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs)); - storageRangeDataRequest.getChildRequests(snapWorldDownloadState, worldStateStorage, null); + storageRangeDataRequest.getChildRequests( + snapWorldDownloadState, worldStateStorageCoordinator, null); verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); } @@ -133,7 +138,7 @@ void markAccountOnInvalidStorageProof() { final List proofs = List.of( - worldStateStorage + worldStateKeyValueStorage .getAccountStorageTrieNode( accountHash, Bytes.EMPTY, stateTrieAccountValue.getStorageRoot()) .get()); @@ -162,7 +167,8 @@ void markAccountOnPartialStorageRange() { new StoredMerklePatriciaTrie<>( new StoredNodeFactory<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode( + accountHash, location, hash), Function.identity(), Function.identity()), stateTrieAccountValue.getStorageRoot()); @@ -200,7 +206,8 @@ void markAccountOnPartialStorageRange() { verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); // should mark during the getchild request - storageRangeDataRequest.getChildRequests(snapWorldDownloadState, worldStateStorage, null); + storageRangeDataRequest.getChildRequests( + snapWorldDownloadState, worldStateStorageCoordinator, null); verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class)); } @@ -215,7 +222,7 @@ void avoidMarkingAccountOnValidStorageTrieNodeDetection() { accountHash, Hash.wrap(accountStateTrie.getRootHash()), Bytes.EMPTY); - storageTrieNodeHealingRequest.getExistingData(snapWorldDownloadState, worldStateStorage); + storageTrieNodeHealingRequest.getExistingData(worldStateStorageCoordinator); verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class)); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java index 7ecd284e98f..43d945a4daa 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStepTest.java @@ -27,7 +27,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountTrieNodeHealingRequest; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.pipeline.Pipe; import org.hyperledger.besu.services.tasks.Task; @@ -58,14 +59,16 @@ public class LoadLocalDataStepTest { private final SnapSyncProcessState snapSyncState = mock(SnapSyncProcessState.class); private final SnapWorldDownloadState downloadState = mock(SnapWorldDownloadState.class); - private final WorldStateStorage worldStateStorage = mock(WorldStateStorage.class); - private final WorldStateStorage.Updater updater = mock(WorldStateStorage.Updater.class); + private final WorldStateStorageCoordinator worldStateStorageCoordinator = + mock(WorldStateStorageCoordinator.class); + private final WorldStateKeyValueStorage.Updater updater = + mock(WorldStateKeyValueStorage.Updater.class); private final SnapSyncConfiguration snapSyncConfiguration = mock(SnapSyncConfiguration.class); private final LoadLocalDataStep loadLocalDataStep = new LoadLocalDataStep( - worldStateStorage, + worldStateStorageCoordinator, downloadState, snapSyncConfiguration, new NoOpMetricsSystem(), @@ -92,8 +95,10 @@ public void shouldReturnStreamWithSameRootHashTaskWhenDataArePresent() { task.getData().setRootHash(blockHeader.getStateRoot()); - when(worldStateStorage.getAccountStateTrieNode(any(), any())).thenReturn(Optional.of(DATA)); - when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + when(worldStateStorageCoordinator.getAccountStateTrieNode(any(), any())) + .thenReturn(Optional.of(DATA)); + when(worldStateStorageCoordinator.updater()) + .thenReturn(mock(WorldStateKeyValueStorage.Updater.class)); final BlockHeader newBlockHeader = new BlockHeaderTestFixture().stateRoot(Hash.EMPTY).buildHeader(); @@ -107,8 +112,9 @@ public void shouldReturnStreamWithSameRootHashTaskWhenDataArePresent() { @Test public void shouldReturnEmptyStreamAndSendTaskToCompletedPipeWhenDataIsPresent() { - when(worldStateStorage.getAccountStateTrieNode(any(), any())).thenReturn(Optional.of(DATA)); - when(worldStateStorage.updater()).thenReturn(updater); + when(worldStateStorageCoordinator.getAccountStateTrieNode(any(), any())) + .thenReturn(Optional.of(DATA)); + when(worldStateStorageCoordinator.updater()).thenReturn(updater); final Stream> output = loadLocalDataStep.loadLocalDataTrieNode(task, completedTasks); @@ -122,7 +128,7 @@ public void shouldReturnEmptyStreamAndSendTaskToCompletedPipeWhenDataIsPresent() // Should not require persisting. request.persist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + worldStateStorageCoordinator, updater, downloadState, snapSyncState, snapSyncConfiguration); verifyNoInteractions(updater); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index d5df4344769..9a53a4418b4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -25,9 +25,10 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.BytecodeRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.Task; import java.util.List; @@ -38,16 +39,18 @@ public class PersistDataStepTest { - private final WorldStateStorage worldStateStorage = + private final WorldStateStorageCoordinator worldStateStorageCoordinator = new InMemoryKeyValueStorageProvider() - .createWorldStateStorage(DataStorageConfiguration.DEFAULT_CONFIG); + .createWorldStateStorageCoordinator(DataStorageConfiguration.DEFAULT_CONFIG); + private final SnapSyncProcessState snapSyncState = mock(SnapSyncProcessState.class); private final SnapWorldDownloadState downloadState = mock(SnapWorldDownloadState.class); private final SnapSyncConfiguration snapSyncConfiguration = mock(SnapSyncConfiguration.class); private final PersistDataStep persistDataStep = - new PersistDataStep(snapSyncState, worldStateStorage, downloadState, snapSyncConfiguration); + new PersistDataStep( + snapSyncState, worldStateStorageCoordinator, downloadState, snapSyncConfiguration); @BeforeEach public void setUp() { @@ -70,7 +73,10 @@ public void shouldSkipPersistDataWhenNoData() { final List> result = persistDataStep.persist(tasks); assertThat(result).isSameAs(tasks); - assertThat(worldStateStorage.getNodeData(Bytes.EMPTY, tasks.get(0).getData().getRootHash())) + assertThat( + worldStateStorageCoordinator + .getStrategy(BonsaiWorldStateKeyValueStorage.class) + .getTrieNodeUnsafe(tasks.get(0).getData().getRootHash())) .isEmpty(); } @@ -81,14 +87,17 @@ private void assertDataPersisted(final List> tasks) { final AccountRangeDataRequest data = (AccountRangeDataRequest) task.getData(); StoredMerklePatriciaTrie trie = new StoredMerklePatriciaTrie<>( - worldStateStorage::getAccountStateTrieNode, data.getRootHash(), b -> b, b -> b); + worldStateStorageCoordinator::getAccountStateTrieNode, + data.getRootHash(), + b -> b, + b -> b); data.getAccounts().forEach((key, value) -> assertThat(trie.get(key)).isPresent()); } else if (task.getData() instanceof StorageRangeDataRequest) { final StorageRangeDataRequest data = (StorageRangeDataRequest) task.getData(); final StoredMerklePatriciaTrie trie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode( + worldStateStorageCoordinator.getAccountStorageTrieNode( Hash.wrap(data.getAccountHash()), location, hash), data.getStorageRoot(), b -> b, @@ -97,8 +106,9 @@ private void assertDataPersisted(final List> tasks) { } else if (task.getData() instanceof BytecodeRequest) { final BytecodeRequest data = (BytecodeRequest) task.getData(); assertThat( - worldStateStorage.getCode( - Hash.wrap(data.getCodeHash()), Hash.wrap(data.getAccountHash()))) + worldStateStorageCoordinator + .getStrategy(BonsaiWorldStateKeyValueStorage.class) + .getCode(Hash.wrap(data.getCodeHash()), Hash.wrap(data.getAccountHash()))) .isPresent(); } else { fail("not expected message"); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java index d4295f55850..40b967096a7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/RangeManagerTest.java @@ -23,7 +23,7 @@ import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.HashMap; @@ -117,11 +117,14 @@ public void testGenerateRangesWithSize3() { @Test public void testFindNewBeginElement() { - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -135,7 +138,7 @@ public void testFindNewBeginElement() { collector, visitor, root, Hash.ZERO)); final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(worldStateStorage); + new WorldStateProofProvider(worldStateStorageCoordinator); // generate the proof final List proofs = @@ -156,11 +159,13 @@ public void testFindNewBeginElement() { @Test public void testFindNewBeginElementWhenNothingIsMissing() { - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -174,7 +179,7 @@ public void testFindNewBeginElementWhenNothingIsMissing() { collector, visitor, root, Hash.ZERO)); final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(worldStateStorage); + new WorldStateProofProvider(worldStateStorageCoordinator); // generate the proof final List proofs = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java index b0995c57a54..0dcc204426a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java @@ -41,7 +41,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -72,7 +73,9 @@ public class SnapWorldDownloadStateTest { private static final int MAX_REQUESTS_WITHOUT_PROGRESS = 10; private static final long MIN_MILLIS_BEFORE_STALLING = 50_000; - private WorldStateStorage worldStateStorage; + private WorldStateKeyValueStorage worldStateKeyValueStorage; + + private WorldStateStorageCoordinator worldStateStorageCoordinator; private final BlockHeader header = new BlockHeaderTestFixture().stateRoot(ROOT_NODE_HASH).buildHeader(); private final InMemoryTasksPriorityQueues pendingRequests = @@ -107,17 +110,20 @@ public void setUp(final DataStorageFormat storageFormat) { when(metricsManager.getMetricsSystem()).thenReturn(new NoOpMetricsSystem()); if (storageFormat == DataStorageFormat.BONSAI) { - worldStateStorage = + worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( new InMemoryKeyValueStorageProvider(), new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); } else { - worldStateStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + worldStateKeyValueStorage = + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); } + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + downloadState = new SnapWorldDownloadState( - worldStateStorage, + worldStateStorageCoordinator, snapContext, blockchain, snapSyncState, @@ -179,7 +185,9 @@ public void shouldStoreRootNodeBeforeReturnedFutureCompletes( final CompletableFuture postFutureChecks = future.thenAccept( result -> - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + assertThat( + worldStateStorageCoordinator.getAccountStateTrieNode( + Bytes.EMPTY, ROOT_NODE_HASH)) .contains(ROOT_NODE_DATA)); downloadState.checkCompletion(header); @@ -204,7 +212,8 @@ public void shouldNotCompleteWhenThereAreAccountPendingTasks( downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } @@ -221,7 +230,8 @@ public void shouldNotCompleteWhenThereAreStoragePendingTasks( downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); downloadState.pendingLargeStorageRequests.add( @@ -231,7 +241,8 @@ public void shouldNotCompleteWhenThereAreStoragePendingTasks( downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } @@ -248,7 +259,8 @@ public void shouldNotCompleteWhenThereAreTriePendingTasks( downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } @@ -266,7 +278,8 @@ public void shouldNotCompleteWhenThereAreFlatDBHealingPendingTasks( downloadState.checkCompletion(header); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } @@ -344,7 +357,8 @@ public void shouldListeningBlockchainDuringHeal( verify(snapSyncState, atLeastOnce()).setHealTrieStatus(true); assertThat(future).isNotDone(); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } @@ -453,13 +467,14 @@ public void shouldNotCompleteReturnedFutureWhenNoPendingTasksRemainAndFlatDBHeal setUp(storageFormat); Assumptions.assumeTrue(storageFormat == DataStorageFormat.BONSAI); Assumptions.assumeTrue(isFlatDbHealingEnabled); - ((BonsaiWorldStateKeyValueStorage) worldStateStorage).upgradeToFullFlatDbMode(); + ((BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage).upgradeToFullFlatDbMode(); when(snapSyncState.isHealTrieInProgress()).thenReturn(true); downloadState.checkCompletion(header); assertThat(future).isNotDone(); verify(snapSyncState).setHealFlatDatabaseInProgress(true); - assertThat(worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)).isEmpty(); + assertThat(worldStateStorageCoordinator.getAccountStateTrieNode(Bytes.EMPTY, ROOT_NODE_HASH)) + .isEmpty(); assertThat(downloadState.isDownloading()).isTrue(); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java index a9790b56660..b1b3800a1be 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrieTest.java @@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.util.List; @@ -41,14 +41,16 @@ public void shouldNotSaveTheRootWhenIncomplete() { final int nbAccounts = 15; - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); - final WorldStateStorage recreatedWorldStateStorage = + final ForestWorldStateKeyValueStorage recreatedWorldStateStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, nbAccounts); + TrieGenerator.generateTrie(worldStateStorageCoordinator, nbAccounts); final StackTrie stackTrie = new StackTrie(Hash.wrap(accountStateTrie.getRootHash()), 0, 256, lastAccount); @@ -66,7 +68,7 @@ public void shouldNotSaveTheRootWhenIncomplete() { collector, visitor, root, lastAccount)); final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(worldStateStorage); + new WorldStateProofProvider(worldStateStorageCoordinator); // generate the proof final List proofs = @@ -78,13 +80,12 @@ public void shouldNotSaveTheRootWhenIncomplete() { stackTrie.addElement(Bytes32.random(), proofs, accounts); - final WorldStateStorage.Updater updater = recreatedWorldStateStorage.updater(); - stackTrie.commit(updater::putAccountStateTrieNode); + final ForestWorldStateKeyValueStorage.Updater updater = recreatedWorldStateStorage.updater(); + stackTrie.commit(((location, hash, value) -> updater.putAccountStateTrieNode(hash, value))); updater.commit(); Assertions.assertThat( - recreatedWorldStateStorage.getAccountStateTrieNode( - Bytes.EMPTY, accountStateTrie.getRootHash())) + recreatedWorldStateStorage.getAccountStateTrieNode(accountStateTrie.getRootHash())) .isEmpty(); } @@ -93,14 +94,16 @@ public void shouldSaveTheRootWhenComplete() { final int nbAccounts = 15; - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); - final WorldStateStorage recreatedWorldStateStorage = + final ForestWorldStateKeyValueStorage recreatedWorldStateStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, nbAccounts); + TrieGenerator.generateTrie(worldStateStorageCoordinator, nbAccounts); final StackTrie stackTrie = new StackTrie(Hash.wrap(accountStateTrie.getRootHash()), 0, 256, lastAccount); @@ -119,7 +122,7 @@ public void shouldSaveTheRootWhenComplete() { collector, visitor, root, lastAccount)); final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(worldStateStorage); + new WorldStateProofProvider(worldStateStorageCoordinator); // generate the proof final List proofs = @@ -131,13 +134,13 @@ public void shouldSaveTheRootWhenComplete() { stackTrie.addElement(Bytes32.random(), proofs, accounts); - final WorldStateStorage.Updater updater = recreatedWorldStateStorage.updater(); - stackTrie.commit(updater::putAccountStateTrieNode); + final ForestWorldStateKeyValueStorage.Updater updater = recreatedWorldStateStorage.updater(); + stackTrie.commit((location, hash, value) -> updater.putAccountStateTrieNode(hash, value)); updater.commit(); } Assertions.assertThat( - worldStateStorage.getAccountStateTrieNode(Bytes.EMPTY, accountStateTrie.getRootHash())) + worldStateKeyValueStorage.getAccountStateTrieNode(accountStateTrie.getRootHash())) .isPresent(); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java index 7d1a4f3db5d..63895f4e6c5 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java @@ -26,10 +26,12 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.TrieIterator; +import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.tasks.Task; import java.util.List; @@ -43,14 +45,19 @@ public class TaskGenerator { public static List> createAccountRequest(final boolean withData) { - final WorldStateStorage worldStateStorage = - new InMemoryKeyValueStorageProvider() - .createWorldStateStorage(DataStorageConfiguration.DEFAULT_CONFIG); + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = + new BonsaiWorldStateKeyValueStorage( + new InMemoryKeyValueStorageProvider(), + new NoOpMetricsSystem(), + DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); final WorldStateProofProvider worldStateProofProvider = - new WorldStateProofProvider(worldStateStorage); + new WorldStateProofProvider(worldStateStorageCoordinator); - final MerkleTrie trie = TrieGenerator.generateTrie(worldStateStorage, 1); + final MerkleTrie trie = + TrieGenerator.generateTrie(worldStateStorageCoordinator, 1); final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( Bytes32.ZERO, RangeManager.MAX_RANGE, 1, Integer.MAX_VALUE); @@ -78,14 +85,14 @@ public static List> createAccountRequest(final boolean wit final StorageRangeDataRequest storageRangeDataRequest = createStorageRangeDataRequest( worldStateProofProvider, - worldStateStorage, + worldStateStorageCoordinator, rootHash, accountHash, stateTrieAccountValue.getStorageRoot(), withData); final BytecodeRequest bytecodeRequest = createBytecodeDataRequest( - worldStateStorage, + worldStateKeyValueStorage, rootHash, accountHash, stateTrieAccountValue.getCodeHash(), @@ -99,7 +106,7 @@ public static List> createAccountRequest(final boolean wit private static StorageRangeDataRequest createStorageRangeDataRequest( final WorldStateProofProvider worldStateProofProvider, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateKeyValueStorage, final Hash rootHash, final Hash accountHash, final Bytes32 storageRoot, @@ -111,7 +118,7 @@ private static StorageRangeDataRequest createStorageRangeDataRequest( final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(accountHash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode(accountHash, location, hash), storageRoot, b -> b, b -> b); @@ -135,7 +142,7 @@ private static StorageRangeDataRequest createStorageRangeDataRequest( } private static BytecodeRequest createBytecodeDataRequest( - final WorldStateStorage worldStateStorage, + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final Hash rootHash, final Hash accountHash, final Hash codeHash, @@ -143,7 +150,7 @@ private static BytecodeRequest createBytecodeDataRequest( final BytecodeRequest request = SnapDataRequest.createBytecodeRequest(accountHash, rootHash, codeHash); if (withData) { - request.setCode(worldStateStorage.getCode(codeHash, accountHash).get()); + request.setCode(worldStateKeyValueStorage.getCode(codeHash, accountHash).get()); } return request; } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java index 70d5118774e..2799d631926 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java @@ -32,7 +32,8 @@ import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -73,11 +74,14 @@ public void setup() { @Test public void shouldReturnChildRequests() { - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); - final WorldStateProofProvider proofProvider = new WorldStateProofProvider(worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + final WorldStateProofProvider proofProvider = + new WorldStateProofProvider(worldStateStorageCoordinator); final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // Create a collector to gather account entries within a specific range final RangeStorageEntriesCollector collector = @@ -114,7 +118,9 @@ public void shouldReturnChildRequests() { // Verify that the start key hash of the snapDataRequest is greater than the last key in the // accounts TreeMap List childRequests = - request.getChildRequests(downloadState, worldStateStorage, snapSyncState).toList(); + request + .getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState) + .toList(); Assertions.assertThat(childRequests).hasSize(1); AccountFlatDatabaseHealingRangeRequest snapDataRequest = (AccountFlatDatabaseHealingRangeRequest) childRequests.get(0); @@ -128,7 +134,9 @@ public void shouldReturnChildRequests() { .map(CompactEncoding::bytesToPath) .collect(Collectors.toList()))); childRequests = - request.getChildRequests(downloadState, worldStateStorage, snapSyncState).toList(); + request + .getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState) + .toList(); Assertions.assertThat(childRequests).hasSizeGreaterThan(1); Assertions.assertThat(childRequests) .hasAtLeastOneElementOfType(AccountFlatDatabaseHealingRangeRequest.class); @@ -138,11 +146,14 @@ public void shouldReturnChildRequests() { @Test public void shouldNotReturnChildRequestsWhenNoMoreAccounts() { - final WorldStateStorage worldStateStorage = + final ForestWorldStateKeyValueStorage worldStateKeyValueStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); - final WorldStateProofProvider proofProvider = new WorldStateProofProvider(worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + final WorldStateProofProvider proofProvider = + new WorldStateProofProvider(worldStateStorageCoordinator); final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // Create a collector to gather account entries within a specific range final RangeStorageEntriesCollector collector = @@ -170,7 +181,7 @@ public void shouldNotReturnChildRequestsWhenNoMoreAccounts() { // Verify that no child requests are returned from the request final Stream childRequests = - request.getChildRequests(downloadState, worldStateStorage, snapSyncState); + request.getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState); Assertions.assertThat(childRequests).isEmpty(); } @@ -179,14 +190,18 @@ public void doNotPersistWhenProofIsValid() { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); - final WorldStateStorage worldStateStorage = + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); - final WorldStateProofProvider proofProvider = new WorldStateProofProvider(worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + final WorldStateProofProvider proofProvider = + new WorldStateProofProvider(worldStateStorageCoordinator); + final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // Create a collector to gather account entries within a specific range final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -221,9 +236,9 @@ public void doNotPersistWhenProofIsValid() { // an ArrayDeque request.addLocalData(proofProvider, accounts, new ArrayDeque<>(proofs)); - WorldStateStorage.Updater updater = Mockito.spy(worldStateStorage.updater()); + WorldStateKeyValueStorage.Updater updater = Mockito.spy(worldStateKeyValueStorage.updater()); request.doPersist( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, @@ -236,14 +251,18 @@ public void doHealAndPersistWhenProofIsInvalid() { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); - final WorldStateStorage worldStateStorage = + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); - final WorldStateProofProvider proofProvider = new WorldStateProofProvider(worldStateStorage); + final WorldStateStorageCoordinator worldStateStorageCoordinator = + new WorldStateStorageCoordinator(worldStateKeyValueStorage); + final WorldStateProofProvider proofProvider = + new WorldStateProofProvider(worldStateStorageCoordinator); + final MerkleTrie accountStateTrie = - TrieGenerator.generateTrie(worldStateStorage, 15); + TrieGenerator.generateTrie(worldStateStorageCoordinator, 15); // Create a collector to gather account entries within a specific range final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -293,9 +312,9 @@ public void doHealAndPersistWhenProofIsInvalid() { request.addLocalData(proofProvider, accounts, new ArrayDeque<>(proofs)); BonsaiWorldStateKeyValueStorage.Updater updater = - (BonsaiWorldStateKeyValueStorage.Updater) Mockito.spy(worldStateStorage.updater()); + Mockito.spy(worldStateKeyValueStorage.updater()); request.doPersist( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java index 704e5b99d4b..41d02651308 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java @@ -35,7 +35,8 @@ import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Iterator; @@ -70,7 +71,9 @@ class StorageFlatDatabaseHealingRangeRequestTest { Address.fromHexString("0xdeadbeeb")); private MerkleTrie trie; - private BonsaiWorldStateKeyValueStorage worldStateStorage; + + private WorldStateStorageCoordinator worldStateStorageCoordinator; + private BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage; private WorldStateProofProvider proofProvider; private Hash account0Hash; private Hash account0StorageRoot; @@ -78,15 +81,18 @@ class StorageFlatDatabaseHealingRangeRequestTest { @BeforeEach public void setup() { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); - worldStateStorage = + + worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( storageProvider, new NoOpMetricsSystem(), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); - proofProvider = new WorldStateProofProvider(worldStateStorage); + worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); + proofProvider = new WorldStateProofProvider(worldStateStorageCoordinator); + trie = TrieGenerator.generateTrie( - worldStateStorage, + worldStateStorageCoordinator, accounts.stream().map(Address::addressHash).collect(Collectors.toList())); account0Hash = accounts.get(0).addressHash(); account0StorageRoot = @@ -103,7 +109,7 @@ void shouldReturnChildRequests() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(account0Hash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode(account0Hash, location, hash), account0StorageRoot, b -> b, b -> b); @@ -147,7 +153,9 @@ void shouldReturnChildRequests() { // Verify that the start key hash of the snapDataRequest is greater than the last key in the // slots TreeMap List childRequests = - request.getChildRequests(downloadState, worldStateStorage, snapSyncState).toList(); + request + .getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState) + .toList(); Assertions.assertThat(childRequests).hasSizeGreaterThan(1); StorageFlatDatabaseHealingRangeRequest snapDataRequest = (StorageFlatDatabaseHealingRangeRequest) childRequests.get(0); @@ -160,7 +168,7 @@ void shouldNotReturnChildRequestsWhenNoMoreSlots() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(account0Hash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode(account0Hash, location, hash), account0StorageRoot, b -> b, b -> b); @@ -191,7 +199,7 @@ void shouldNotReturnChildRequestsWhenNoMoreSlots() { // Verify that no child requests are returned from the request final Stream childRequests = - request.getChildRequests(downloadState, worldStateStorage, snapSyncState); + request.getChildRequests(downloadState, worldStateStorageCoordinator, snapSyncState); Assertions.assertThat(childRequests).isEmpty(); } @@ -201,7 +209,7 @@ void doNotPersistWhenProofIsValid() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(account0Hash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode(account0Hash, location, hash), account0StorageRoot, b -> b, b -> b); @@ -242,9 +250,9 @@ void doNotPersistWhenProofIsValid() { // Add local data to the request request.addLocalData(proofProvider, slots, new ArrayDeque<>(proofs)); - WorldStateStorage.Updater updater = Mockito.spy(worldStateStorage.updater()); + WorldStateKeyValueStorage.Updater updater = Mockito.spy(worldStateKeyValueStorage.updater()); request.doPersist( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, @@ -258,7 +266,7 @@ void doHealAndPersistWhenProofIsInvalid() { final StoredMerklePatriciaTrie storageTrie = new StoredMerklePatriciaTrie<>( (location, hash) -> - worldStateStorage.getAccountStorageTrieNode(account0Hash, location, hash), + worldStateKeyValueStorage.getAccountStorageTrieNode(account0Hash, location, hash), account0StorageRoot, b -> b, b -> b); @@ -313,9 +321,9 @@ void doHealAndPersistWhenProofIsInvalid() { request.addLocalData(proofProvider, slots, new ArrayDeque<>(proofs)); BonsaiWorldStateKeyValueStorage.Updater updater = - (BonsaiWorldStateKeyValueStorage.Updater) Mockito.spy(worldStateStorage.updater()); + Mockito.spy(worldStateKeyValueStorage.updater()); request.doPersist( - worldStateStorage, + worldStateStorageCoordinator, updater, downloadState, snapSyncState, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java index 847e624ca0c..1f87a2d783e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.TrieGenerator; -import org.hyperledger.besu.ethereum.eth.sync.snapsync.SnapWorldDownloadState; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.trie.MerkleTrie; @@ -26,7 +25,7 @@ import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -43,13 +42,11 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) class StorageTrieNodeHealingRequestTest { - @Mock private SnapWorldDownloadState downloadState; final List
accounts = List.of( Address.fromHexString("0xdeadbeef"), @@ -57,7 +54,7 @@ class StorageTrieNodeHealingRequestTest { Address.fromHexString("0xdeadbeea"), Address.fromHexString("0xdeadbeeb")); - private WorldStateStorage worldStateStorage; + private WorldStateStorageCoordinator worldStateStorageCoordinator; private Hash account0Hash; private Hash account0StorageRoot; @@ -71,18 +68,21 @@ public Stream provideArguments(final ExtensionContext conte public void setup(final DataStorageFormat storageFormat) { if (storageFormat.equals(DataStorageFormat.FOREST)) { - worldStateStorage = new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()); + worldStateStorageCoordinator = + new WorldStateStorageCoordinator( + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage())); } else { final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); - worldStateStorage = - new BonsaiWorldStateKeyValueStorage( - storageProvider, - new NoOpMetricsSystem(), - DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); + worldStateStorageCoordinator = + new WorldStateStorageCoordinator( + new BonsaiWorldStateKeyValueStorage( + storageProvider, + new NoOpMetricsSystem(), + DataStorageConfiguration.DEFAULT_BONSAI_CONFIG)); } final MerkleTrie trie = TrieGenerator.generateTrie( - worldStateStorage, + worldStateStorageCoordinator, accounts.stream().map(Address::addressHash).collect(Collectors.toList())); account0Hash = accounts.get(0).addressHash(); @@ -103,7 +103,7 @@ void shouldDetectExistingData(final DataStorageFormat storageFormat) { new StorageTrieNodeHealingRequest( account0StorageRoot, account0Hash, Hash.EMPTY, Bytes.EMPTY); - Assertions.assertThat(request.getExistingData(downloadState, worldStateStorage)).isPresent(); + Assertions.assertThat(request.getExistingData(worldStateStorageCoordinator)).isPresent(); } @ParameterizedTest @@ -113,6 +113,6 @@ void shouldDetectMissingData(final DataStorageFormat storageFormat) { final StorageTrieNodeHealingRequest request = new StorageTrieNodeHealingRequest(Hash.EMPTY, account0Hash, Hash.EMPTY, Bytes.EMPTY); - Assertions.assertThat(request.getExistingData(downloadState, worldStateStorage)).isEmpty(); + Assertions.assertThat(request.getExistingData(worldStateStorageCoordinator)).isEmpty(); } } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java index 86f9b5e2cc7..9ff360cd549 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/BlockchainModule.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -57,7 +57,7 @@ Blockchain provideBlockchain( @Singleton MutableWorldState getMutableWorldState( @Named("StateRoot") final Bytes32 stateRoot, - final WorldStateStorage worldStateStorage, + final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStatePreimageStorage worldStatePreimageStorage, final GenesisState genesisState, @Named("KeyValueStorageName") final String keyValueStorageName, @@ -65,20 +65,25 @@ MutableWorldState getMutableWorldState( if ("memory".equals(keyValueStorageName)) { final MutableWorldState mutableWorldState = new ForestMutableWorldState( - worldStateStorage, worldStatePreimageStorage, evmConfiguration); + worldStateStorageCoordinator.worldStateKeyValueStorage(), + worldStatePreimageStorage, + evmConfiguration); genesisState.writeStateTo(mutableWorldState); return mutableWorldState; } else { return new ForestMutableWorldState( - stateRoot, worldStateStorage, worldStatePreimageStorage, evmConfiguration); + stateRoot, + worldStateStorageCoordinator.worldStateKeyValueStorage(), + worldStatePreimageStorage, + evmConfiguration); } } @Provides @Singleton - WorldStateStorage provideWorldStateStorage( + WorldStateStorageCoordinator provideWorldStateStorage( @Named("worldState") final KeyValueStorage keyValueStorage) { - return new ForestWorldStateKeyValueStorage(keyValueStorage); + return new WorldStateStorageCoordinator(new ForestWorldStateKeyValueStorage(keyValueStorage)); } @Provides 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 dc90d4889a7..1c536e96a38 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 @@ -53,19 +53,19 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState private final EvmConfiguration evmConfiguration; protected BonsaiReferenceTestWorldState( - final BonsaiReferenceTestWorldStateStorage worldStateStorage, + final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage, final CachedMerkleTrieLoader cachedMerkleTrieLoader, final CachedWorldStorageManager cachedWorldStorageManager, final TrieLogManager trieLogManager, final BonsaiPreImageProxy preImageProxy, final EvmConfiguration evmConfiguration) { super( - worldStateStorage, + worldStateKeyValueStorage, cachedMerkleTrieLoader, cachedWorldStorageManager, trieLogManager, evmConfiguration); - this.refTestStorage = worldStateStorage; + this.refTestStorage = worldStateKeyValueStorage; this.preImageProxy = preImageProxy; this.evmConfiguration = evmConfiguration; setAccumulator( @@ -82,7 +82,8 @@ protected BonsaiReferenceTestWorldState( @Override public ReferenceTestWorldState copy() { - var layerCopy = new BonsaiReferenceTestWorldStateStorage(worldStateStorage, preImageProxy); + var layerCopy = + new BonsaiReferenceTestWorldStateStorage(worldStateKeyValueStorage, preImageProxy); return new BonsaiReferenceTestWorldState( layerCopy, cachedMerkleTrieLoader, @@ -186,7 +187,7 @@ private void generateTrieLogFromState( private BonsaiWorldState createBonsaiWorldState(final boolean isFrozen) { BonsaiWorldState bonsaiWorldState = new BonsaiWorldState( - new BonsaiWorldStateLayerStorage(worldStateStorage), + new BonsaiWorldStateLayerStorage(worldStateKeyValueStorage), cachedMerkleTrieLoader, cachedWorldStorageManager, trieLogManager, @@ -219,7 +220,7 @@ public static BonsaiReferenceTestWorldState create( metricsSystem, DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); - final BonsaiReferenceTestWorldStateStorage worldStateStorage = + final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage = new BonsaiReferenceTestWorldStateStorage(bonsaiWorldStateKeyValueStorage, preImageProxy); final NoOpCachedWorldStorageManager noOpCachedWorldStorageManager = @@ -227,7 +228,7 @@ public static BonsaiReferenceTestWorldState create( final BonsaiReferenceTestWorldState worldState = new BonsaiReferenceTestWorldState( - worldStateStorage, + worldStateKeyValueStorage, cachedMerkleTrieLoader, noOpCachedWorldStorageManager, trieLogManager, diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index 4b142464247..a9b5050be37 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -64,6 +64,7 @@ import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; @@ -170,7 +171,8 @@ private boolean buildContext( final WorldStateArchive worldStateArchive = new ForestWorldStateArchive( - new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage()), + new WorldStateStorageCoordinator( + new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage())), new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), EvmConfiguration.DEFAULT); final MutableWorldState worldState = worldStateArchive.getMutable(); diff --git a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java index 6b931d041e5..09ddc1b2608 100644 --- a/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java +++ b/ethereum/trie/src/test/java/org/hyperledger/besu/ethereum/trie/RangeStorageEntriesCollectorTest.java @@ -28,10 +28,11 @@ public class RangeStorageEntriesCollectorTest { @Test public void shouldRetrieveAllLeavesInRangeWhenStartFromZero() { - InMemoryKeyValueStorage worldStateStorage = new InMemoryKeyValueStorage(); + InMemoryKeyValueStorage worldStateKeyValueStorage = new InMemoryKeyValueStorage(); final MerkleTrie accountStateTrie = new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), + (location, hash) -> + worldStateKeyValueStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), b -> b, b -> b); final List lists = @@ -47,10 +48,11 @@ public void shouldRetrieveAllLeavesInRangeWhenStartFromZero() { @Test public void shouldRetrieveAllLeavesInRangeWhenStartFromSpecificRange() { - InMemoryKeyValueStorage worldStateStorage = new InMemoryKeyValueStorage(); + InMemoryKeyValueStorage worldStateKeyValueStorage = new InMemoryKeyValueStorage(); final MerkleTrie accountStateTrie = new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), + (location, hash) -> + worldStateKeyValueStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), b -> b, b -> b); final List lists = @@ -66,10 +68,11 @@ public void shouldRetrieveAllLeavesInRangeWhenStartFromSpecificRange() { @Test public void shouldExcludeLeavesNotInRange() { - InMemoryKeyValueStorage worldStateStorage = new InMemoryKeyValueStorage(); + InMemoryKeyValueStorage worldStateKeyValueStorage = new InMemoryKeyValueStorage(); final MerkleTrie accountStateTrie = new StoredMerklePatriciaTrie<>( - (location, hash) -> worldStateStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), + (location, hash) -> + worldStateKeyValueStorage.get(hash.toArrayUnsafe()).map(Bytes::wrap), b -> b, b -> b); final List lists =