storage format refactor for preparing verkle trie integration (#6721)

Splitting Bonsai code: This commit aims to divide Bonsai into two packages

- Common Classes with a Prefix: The common part will include classes prefixed with "DiffBased." These classes are designed to provide a base for both Bonsai and any future storage format that might use this diff-based approach.

- Bonsai's Specifics: Bonsai will retain its unique features in its own package. This means that while it shares the diff-based infrastructure with the common part, it also has its own specific functionalities that are not shared with other storage format.

- Extension to Verkle: this modification add the possibility of adding "Verkle" as a new storage format based on the diff-based architecture. Like Bonsai, Verkle would use the common diff-based classes but also have its own specific features.

---------

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
Signed-off-by: Karim Taam <karim.t2am@gmail.com>
pull/6832/head develop
Karim TAAM 8 months ago committed by GitHub
parent 7e46889817
commit f2c2512ef6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelper.java
  2. 4
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java
  3. 8
      besu/src/main/java/org/hyperledger/besu/components/BesuComponent.java
  4. 23
      besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java
  5. 6
      besu/src/test/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogHelperTest.java
  6. 8
      besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java
  7. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/AccountAdapter.java
  8. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
  9. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/storage/keyvalue/KeyValueStorageProvider.java
  10. 18
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/common/GenesisWorldStateProvider.java
  11. 185
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiAccount.java
  12. 145
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProvider.java
  13. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedMerkleTrieLoader.java
  14. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedMerkleTrieLoaderModule.java
  15. 60
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/BonsaiCachedWorldStorageManager.java
  16. 18
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoOpBonsaiCachedWorldStorageManager.java
  17. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiPreImageProxy.java
  18. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiSnapshotWorldStateKeyValueStorage.java
  19. 188
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorage.java
  20. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateLayerStorage.java
  21. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/flat/FullFlatDbStrategy.java
  22. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/flat/PartialFlatDbStrategy.java
  23. 19
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogFactoryImpl.java
  24. 361
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java
  25. 98
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateUpdateAccumulator.java
  26. 206
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedAccount.java
  27. 25
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedValue.java
  28. 171
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java
  29. 25
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/StorageSubscriber.java
  30. 97
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldStorageManager.java
  31. 22
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/cache/DiffBasedCachedWorldView.java
  32. 22
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedLayeredWorldStateKeyValueStorage.java
  33. 21
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedSnapshotWorldStateKeyValueStorage.java
  34. 234
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/DiffBasedWorldStateKeyValueStorage.java
  35. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/AccountHashCodeStorageStrategy.java
  36. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/CodeHashCodeStorageStrategy.java
  37. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/CodeStorageStrategy.java
  38. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/FlatDbStrategy.java
  39. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/FlatDbStrategyProvider.java
  40. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/NoOpTrieLogManager.java
  41. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogAddedEvent.java
  42. 50
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogLayer.java
  43. 23
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogManager.java
  44. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java
  45. 334
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldState.java
  46. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/DiffBasedWorldView.java
  47. 339
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java
  48. 49
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/preload/AccountConsumingMap.java
  49. 21
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/preload/Consumer.java
  50. 53
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/preload/StorageConsumingMap.java
  51. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/worldstate/WorldStateStorageCoordinator.java
  52. 12
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/InMemoryKeyValueStorageProvider.java
  53. 2
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TrieGenerator.java
  54. 6
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/BlockImportExceptionHandlingTest.java
  55. 8
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java
  56. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiCachedMerkleTrieLoaderTest.java
  57. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiSnapshotIsolationTests.java
  58. 36
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/BonsaiWorldStateProviderTest.java
  59. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/LogRollingTests.java
  60. 12
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/RollingImport.java
  61. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/storage/BonsaiWorldStateKeyValueStorageTest.java
  62. 3
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogFactoryTests.java
  63. 9
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogManagerTests.java
  64. 7
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogPrunerTest.java
  65. 30
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldStateTest.java
  66. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/common/storage/flat/FlatDbStrategyProviderTest.java
  67. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogLayerTests.java
  68. 1
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/forest/storage/ForestKeyValueStorageWorldStateStorageTest.java
  69. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java
  70. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloader.java
  71. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java
  72. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadState.java
  73. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloader.java
  74. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java
  75. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java
  76. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequest.java
  77. 2
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequest.java
  78. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java
  79. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java
  80. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloaderTest.java
  81. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastWorldDownloadStateTest.java
  82. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/LoadLocalDataStepTest.java
  83. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java
  84. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java
  85. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldDownloadStateTest.java
  86. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java
  87. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/AccountFlatDatabaseHealingRangeRequestTest.java
  88. 3
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageFlatDatabaseHealingRangeRequestTest.java
  89. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/StorageTrieNodeHealingRequestTest.java
  90. 18
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestUpdateAccumulator.java
  91. 58
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldState.java
  92. 12
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BonsaiReferenceTestWorldStateStorage.java
  93. 2
      gradle.properties

@ -27,9 +27,9 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import java.io.File; import java.io.File;

@ -25,8 +25,8 @@ import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogPruner; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogPruner;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;

@ -19,8 +19,8 @@ package org.hyperledger.besu.components;
import org.hyperledger.besu.cli.BesuCommand; import org.hyperledger.besu.cli.BesuCommand;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.BlobCache;
import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule; import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoaderModule; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoaderModule;
import org.hyperledger.besu.metrics.MetricsSystemModule; import org.hyperledger.besu.metrics.MetricsSystemModule;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BesuPluginContextImpl;
@ -37,7 +37,7 @@ import org.slf4j.Logger;
modules = { modules = {
BesuCommandModule.class, BesuCommandModule.class,
MetricsSystemModule.class, MetricsSystemModule.class,
CachedMerkleTrieLoaderModule.class, BonsaiCachedMerkleTrieLoaderModule.class,
BesuPluginContextModule.class, BesuPluginContextModule.class,
BlobCacheModule.class BlobCacheModule.class
}) })
@ -55,7 +55,7 @@ public interface BesuComponent {
* *
* @return CachedMerkleTrieLoader * @return CachedMerkleTrieLoader
*/ */
CachedMerkleTrieLoader getCachedMerkleTrieLoader(); BonsaiCachedMerkleTrieLoader getCachedMerkleTrieLoader();
/** /**
* a metrics system that is observable by a Prometheus or OTEL metrics collection subsystem * a metrics system that is observable by a Prometheus or OTEL metrics collection subsystem

@ -81,11 +81,11 @@ import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration;
import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogPruner; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogPruner;
import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive;
import org.hyperledger.besu.ethereum.trie.forest.pruner.MarkSweepPruner; import org.hyperledger.besu.ethereum.trie.forest.pruner.MarkSweepPruner;
import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner; import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner;
@ -576,13 +576,14 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
dataDirectory.toString(), dataDirectory.toString(),
numberOfBlocksToCache); numberOfBlocksToCache);
final CachedMerkleTrieLoader cachedMerkleTrieLoader = final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader =
besuComponent besuComponent
.map(BesuComponent::getCachedMerkleTrieLoader) .map(BesuComponent::getCachedMerkleTrieLoader)
.orElseGet(() -> new CachedMerkleTrieLoader(metricsSystem)); .orElseGet(() -> new BonsaiCachedMerkleTrieLoader(metricsSystem));
final WorldStateArchive worldStateArchive = final WorldStateArchive worldStateArchive =
createWorldStateArchive(worldStateStorageCoordinator, blockchain, cachedMerkleTrieLoader); createWorldStateArchive(
worldStateStorageCoordinator, blockchain, bonsaiCachedMerkleTrieLoader);
if (blockchain.getChainHeadBlockNumber() < 1) { if (blockchain.getChainHeadBlockNumber() < 1) {
genesisState.writeStateTo(worldStateArchive.getMutable()); genesisState.writeStateTo(worldStateArchive.getMutable());
@ -1048,7 +1049,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
WorldStateArchive createWorldStateArchive( WorldStateArchive createWorldStateArchive(
final WorldStateStorageCoordinator worldStateStorageCoordinator, final WorldStateStorageCoordinator worldStateStorageCoordinator,
final Blockchain blockchain, final Blockchain blockchain,
final CachedMerkleTrieLoader cachedMerkleTrieLoader) { final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader) {
return switch (dataStorageConfiguration.getDataStorageFormat()) { return switch (dataStorageConfiguration.getDataStorageFormat()) {
case BONSAI -> { case BONSAI -> {
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
@ -1057,7 +1058,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
worldStateKeyValueStorage, worldStateKeyValueStorage,
blockchain, blockchain,
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()), Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null), besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration); evmConfiguration);
} }
@ -1067,6 +1068,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides
yield new ForestWorldStateArchive( yield new ForestWorldStateArchive(
worldStateStorageCoordinator, preimageStorage, evmConfiguration); worldStateStorageCoordinator, preimageStorage, evmConfiguration);
} }
default -> throw new IllegalStateException(
"Unexpected value: " + dataStorageConfiguration.getDataStorageFormat());
}; };
} }

@ -31,9 +31,9 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;

@ -43,9 +43,9 @@ import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage;
import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration; import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
@ -189,7 +189,7 @@ public class BesuControllerBuilderTest {
.createWorldStateArchive( .createWorldStateArchive(
any(WorldStateStorageCoordinator.class), any(WorldStateStorageCoordinator.class),
any(Blockchain.class), any(Blockchain.class),
any(CachedMerkleTrieLoader.class)); any(BonsaiCachedMerkleTrieLoader.class));
doReturn(mockWorldState).when(worldStateArchive).getMutable(); doReturn(mockWorldState).when(worldStateArchive).getMutable();
when(storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration)) when(storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration))
.thenReturn(new WorldStateStorageCoordinator(bonsaiWorldStateStorage)); .thenReturn(new WorldStateStorageCoordinator(bonsaiWorldStateStorage));

@ -17,7 +17,7 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.AccountState; import org.hyperledger.besu.evm.account.AccountState;

@ -31,8 +31,8 @@ import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;

@ -19,7 +19,7 @@ import org.hyperledger.besu.ethereum.chain.VariablesStorage;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -19,11 +19,11 @@ package org.hyperledger.besu.ethereum.trie.common;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.NoOpCachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoOpBonsaiCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.NoOpTrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.NoOpTrieLogManager;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
@ -59,8 +59,8 @@ public class GenesisWorldStateProvider {
* @return a mutable world state for the Genesis block * @return a mutable world state for the Genesis block
*/ */
private static MutableWorldState createGenesisBonsaiWorldState() { private static MutableWorldState createGenesisBonsaiWorldState() {
final CachedMerkleTrieLoader cachedMerkleTrieLoader = final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader =
new CachedMerkleTrieLoader(new NoOpMetricsSystem()); new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem());
final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage = final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage =
new BonsaiWorldStateKeyValueStorage( new BonsaiWorldStateKeyValueStorage(
new KeyValueStorageProvider( new KeyValueStorageProvider(
@ -71,8 +71,8 @@ public class GenesisWorldStateProvider {
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
return new BonsaiWorldState( return new BonsaiWorldState(
bonsaiWorldStateKeyValueStorage, bonsaiWorldStateKeyValueStorage,
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
new NoOpCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage), new NoOpBonsaiCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage),
new NoOpTrieLogManager(), new NoOpTrieLogManager(),
EvmConfiguration.DEFAULT); EvmConfiguration.DEFAULT);
} }

@ -14,48 +14,34 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import org.hyperledger.besu.datatypes.AccountValue; import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPException;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldView; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedAccount;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.evm.ModificationNotAllowedException; import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount; import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap; import java.util.NavigableMap;
import java.util.Objects; import java.util.Objects;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
public class BonsaiAccount implements MutableAccount, AccountValue { public class BonsaiAccount extends DiffBasedAccount {
private final BonsaiWorldView context;
private boolean immutable;
private final Address address;
private final Hash addressHash;
private Hash codeHash;
private long nonce;
private Wei balance;
private Hash storageRoot; private Hash storageRoot;
private Bytes code;
private final Map<UInt256, UInt256> updatedStorage = new HashMap<>();
public BonsaiAccount( public BonsaiAccount(
final BonsaiWorldView context, final DiffBasedWorldView context,
final Address address, final Address address,
final Hash addressHash, final Hash addressHash,
final long nonce, final long nonce,
@ -63,31 +49,24 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
final Hash storageRoot, final Hash storageRoot,
final Hash codeHash, final Hash codeHash,
final boolean mutable) { final boolean mutable) {
this.context = context; super(context, address, addressHash, nonce, balance, codeHash, mutable);
this.address = address;
this.addressHash = addressHash;
this.nonce = nonce;
this.balance = balance;
this.storageRoot = storageRoot; this.storageRoot = storageRoot;
this.codeHash = codeHash;
this.immutable = !mutable;
} }
public BonsaiAccount( public BonsaiAccount(
final BonsaiWorldView context, final DiffBasedWorldView context,
final Address address, final Address address,
final AccountValue stateTrieAccount, final AccountValue stateTrieAccount,
final boolean mutable) { final boolean mutable) {
this( super(
context, context,
address, address,
address.addressHash(), address.addressHash(),
stateTrieAccount.getNonce(), stateTrieAccount.getNonce(),
stateTrieAccount.getBalance(), stateTrieAccount.getBalance(),
stateTrieAccount.getStorageRoot(),
stateTrieAccount.getCodeHash(), stateTrieAccount.getCodeHash(),
mutable); mutable);
this.storageRoot = stateTrieAccount.getStorageRoot();
} }
public BonsaiAccount(final BonsaiAccount toCopy) { public BonsaiAccount(final BonsaiAccount toCopy) {
@ -95,37 +74,35 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
} }
public BonsaiAccount( public BonsaiAccount(
final BonsaiAccount toCopy, final BonsaiWorldView context, final boolean mutable) { final BonsaiAccount toCopy, final DiffBasedWorldView context, final boolean mutable) {
this.context = context; super(
this.address = toCopy.address; context,
this.addressHash = toCopy.addressHash; toCopy.address,
this.nonce = toCopy.nonce; toCopy.addressHash,
this.balance = toCopy.balance; toCopy.nonce,
toCopy.balance,
toCopy.codeHash,
mutable);
this.storageRoot = toCopy.storageRoot; this.storageRoot = toCopy.storageRoot;
this.codeHash = toCopy.codeHash;
this.code = toCopy.code;
updatedStorage.putAll(toCopy.updatedStorage); updatedStorage.putAll(toCopy.updatedStorage);
this.immutable = !mutable;
} }
public BonsaiAccount( public BonsaiAccount(
final BonsaiWorldView context, final UpdateTrackingAccount<BonsaiAccount> tracked) { final DiffBasedWorldView context, final UpdateTrackingAccount<BonsaiAccount> tracked) {
this.context = context; super(
this.address = tracked.getAddress(); context,
this.addressHash = tracked.getAddressHash(); tracked.getAddress(),
this.nonce = tracked.getNonce(); tracked.getAddressHash(),
this.balance = tracked.getBalance(); tracked.getNonce(),
tracked.getBalance(),
tracked.getCodeHash(),
true);
this.storageRoot = Hash.EMPTY_TRIE_HASH; this.storageRoot = Hash.EMPTY_TRIE_HASH;
this.codeHash = tracked.getCodeHash();
this.code = tracked.getCode();
updatedStorage.putAll(tracked.getUpdatedStorage()); updatedStorage.putAll(tracked.getUpdatedStorage());
this.immutable = false;
} }
public static BonsaiAccount fromRLP( public static BonsaiAccount fromRLP(
final BonsaiWorldView context, final DiffBasedWorldView context,
final Address address, final Address address,
final Bytes encoded, final Bytes encoded,
final boolean mutable) final boolean mutable)
@ -144,88 +121,11 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
context, address, address.addressHash(), nonce, balance, storageRoot, codeHash, mutable); context, address, address.addressHash(), nonce, balance, storageRoot, codeHash, mutable);
} }
@Override
public Address getAddress() {
return address;
}
@Override
public Hash getAddressHash() {
return addressHash;
}
@Override
public long getNonce() {
return nonce;
}
@Override
public void setNonce(final long value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
nonce = value;
}
@Override
public Wei getBalance() {
return balance;
}
@Override
public void setBalance(final Wei value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
balance = value;
}
@Override
public Bytes getCode() {
if (code == null) {
code = context.getCode(address, codeHash).orElse(Bytes.EMPTY);
}
return code;
}
@Override
public void setCode(final Bytes code) {
if (immutable) {
throw new ModificationNotAllowedException();
}
this.code = code;
if (code == null || code.isEmpty()) {
this.codeHash = Hash.EMPTY;
} else {
this.codeHash = Hash.hash(code);
}
}
@Override
public Hash getCodeHash() {
return codeHash;
}
@Override
public UInt256 getStorageValue(final UInt256 key) {
return context.getStorageValue(address, key);
}
@Override
public UInt256 getOriginalStorageValue(final UInt256 key) {
return context.getPriorStorageValue(address, key);
}
@Override @Override
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom( public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
final Bytes32 startKeyHash, final int limit) { final Bytes32 startKeyHash, final int limit) {
return context.getWorldStateStorage().storageEntriesFrom(this.addressHash, startKeyHash, limit); return ((BonsaiWorldStateKeyValueStorage) context.getWorldStateStorage())
} .storageEntriesFrom(this.addressHash, startKeyHash, limit);
public Bytes serializeAccount() {
final BytesValueRLPOutput out = new BytesValueRLPOutput();
writeTo(out);
return out.encoded();
} }
@Override @Override
@ -240,24 +140,6 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
out.endList(); out.endList();
} }
@Override
public void setStorageValue(final UInt256 key, final UInt256 value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
updatedStorage.put(key, value);
}
@Override
public void clearStorage() {
updatedStorage.clear();
}
@Override
public Map<UInt256, UInt256> getUpdatedStorage() {
return updatedStorage;
}
@Override @Override
public Hash getStorageRoot() { public Hash getStorageRoot() {
return storageRoot; return storageRoot;
@ -270,11 +152,6 @@ public class BonsaiAccount implements MutableAccount, AccountValue {
this.storageRoot = storageRoot; this.storageRoot = storageRoot;
} }
@Override
public void becomeImmutable() {
immutable = true;
}
@Override @Override
public String toString() { public String toString() {
return "AccountState{" return "AccountState{"

@ -0,0 +1,145 @@
/*
* 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.trie.diffbased.bonsai;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.plugin.BesuContext;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BonsaiWorldStateProvider extends DiffBasedWorldStateProvider {
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateProvider.class);
private final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader;
public BonsaiWorldStateProvider(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final Blockchain blockchain,
final Optional<Long> maxLayersToLoad,
final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader,
final BesuContext pluginContext,
final EvmConfiguration evmConfiguration) {
super(worldStateKeyValueStorage, blockchain, maxLayersToLoad, pluginContext);
this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader;
provideCachedWorldStorageManager(
new BonsaiCachedWorldStorageManager(this, worldStateKeyValueStorage));
loadPersistedState(new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration));
}
@VisibleForTesting
BonsaiWorldStateProvider(
final BonsaiCachedWorldStorageManager bonsaiCachedWorldStorageManager,
final TrieLogManager trieLogManager,
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final Blockchain blockchain,
final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader,
final EvmConfiguration evmConfiguration) {
super(worldStateKeyValueStorage, blockchain, trieLogManager);
this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader;
provideCachedWorldStorageManager(bonsaiCachedWorldStorageManager);
loadPersistedState(new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration));
}
public BonsaiCachedMerkleTrieLoader getCachedMerkleTrieLoader() {
return bonsaiCachedMerkleTrieLoader;
}
private BonsaiWorldStateKeyValueStorage getWorldStateKeyValueStorage() {
return (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage;
}
/**
* Prepares the state healing process for a given address and location. It prepares the state
* healing, including retrieving data from storage, identifying invalid slots or nodes, removing
* account and slot from the state trie, and committing the changes. Finally, it downgrades the
* world state storage to partial flat database mode.
*/
public void prepareStateHealing(final Address address, final Bytes location) {
final Set<Bytes> keysToDelete = new HashSet<>();
final BonsaiWorldStateKeyValueStorage.Updater updater =
getWorldStateKeyValueStorage().updater();
final Hash accountHash = address.addressHash();
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie =
new StoredMerklePatriciaTrie<>(
(l, h) -> {
final Optional<Bytes> node =
getWorldStateKeyValueStorage().getAccountStateTrieNode(l, h);
if (node.isPresent()) {
keysToDelete.add(l);
}
return node;
},
persistedState.getWorldStateRootHash(),
Function.identity(),
Function.identity());
try {
accountTrie
.get(accountHash)
.map(RLP::input)
.map(StateTrieAccountValue::readFrom)
.ifPresent(
account -> {
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
(l, h) -> {
Optional<Bytes> node =
getWorldStateKeyValueStorage()
.getAccountStorageTrieNode(accountHash, l, h);
if (node.isPresent()) {
keysToDelete.add(Bytes.concatenate(accountHash, l));
}
return node;
},
account.getStorageRoot(),
Function.identity(),
Function.identity());
try {
storageTrie.getPath(location);
} catch (Exception eA) {
LOG.warn("Invalid slot found for account {} at location {}", address, location);
// ignore
}
});
} catch (Exception eA) {
LOG.warn("Invalid node for account {} at location {}", address, location);
// ignore
}
keysToDelete.forEach(updater::removeAccountStateTrieNode);
updater.commit();
getWorldStateKeyValueStorage().downgradeToPartialFlatDbMode();
}
}

@ -13,14 +13,15 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
@ -37,8 +38,7 @@ import io.prometheus.client.guava.cache.CacheMetricsCollector;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
public class CachedMerkleTrieLoader public class BonsaiCachedMerkleTrieLoader implements StorageSubscriber {
implements BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber {
private static final int ACCOUNT_CACHE_SIZE = 100_000; private static final int ACCOUNT_CACHE_SIZE = 100_000;
private static final int STORAGE_CACHE_SIZE = 200_000; private static final int STORAGE_CACHE_SIZE = 200_000;
@ -47,7 +47,7 @@ public class CachedMerkleTrieLoader
private final Cache<Bytes, Bytes> storageNodes = private final Cache<Bytes, Bytes> storageNodes =
CacheBuilder.newBuilder().recordStats().maximumSize(STORAGE_CACHE_SIZE).build(); CacheBuilder.newBuilder().recordStats().maximumSize(STORAGE_CACHE_SIZE).build();
public CachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) { public BonsaiCachedMerkleTrieLoader(final ObservableMetricsSystem metricsSystem) {
CacheMetricsCollector cacheMetrics = new CacheMetricsCollector(); CacheMetricsCollector cacheMetrics = new CacheMetricsCollector();
cacheMetrics.addCache("accountsNodes", accountNodes); cacheMetrics.addCache("accountsNodes", accountNodes);

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache;
import org.hyperledger.besu.metrics.ObservableMetricsSystem; import org.hyperledger.besu.metrics.ObservableMetricsSystem;
@ -21,11 +21,11 @@ import dagger.Module;
import dagger.Provides; import dagger.Provides;
@Module @Module
public class CachedMerkleTrieLoaderModule { public class BonsaiCachedMerkleTrieLoaderModule {
@Provides @Provides
CachedMerkleTrieLoader provideCachedMerkleTrieLoaderModule( BonsaiCachedMerkleTrieLoader provideCachedMerkleTrieLoaderModule(
final ObservableMetricsSystem metricsSystem) { final ObservableMetricsSystem metricsSystem) {
return new CachedMerkleTrieLoader(metricsSystem); return new BonsaiCachedMerkleTrieLoader(metricsSystem);
} }
} }

@ -0,0 +1,60 @@
/*
* 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.trie.diffbased.bonsai.cache;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiSnapshotWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateLayerStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
public class BonsaiCachedWorldStorageManager extends DiffBasedCachedWorldStorageManager {
public BonsaiCachedWorldStorageManager(
final BonsaiWorldStateProvider archive,
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) {
super(archive, worldStateKeyValueStorage);
}
@Override
public DiffBasedWorldState createWorldState(
final DiffBasedWorldStateProvider archive,
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final EvmConfiguration evmConfiguration) {
return new BonsaiWorldState(
(BonsaiWorldStateProvider) archive,
(BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage,
evmConfiguration);
}
@Override
public DiffBasedWorldStateKeyValueStorage createLayeredKeyValueStorage(
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) {
return new BonsaiWorldStateLayerStorage(
(BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage);
}
@Override
public DiffBasedWorldStateKeyValueStorage createSnapshotKeyValueStorage(
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) {
return new BonsaiSnapshotWorldStateKeyValueStorage(
(BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage);
}
}

@ -12,19 +12,19 @@
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
public class NoOpCachedWorldStorageManager extends CachedWorldStorageManager { public class NoOpBonsaiCachedWorldStorageManager extends BonsaiCachedWorldStorageManager {
public NoOpCachedWorldStorageManager( public NoOpBonsaiCachedWorldStorageManager(
final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage) { final BonsaiWorldStateKeyValueStorage bonsaiWorldStateKeyValueStorage) {
super(null, bonsaiWorldStateKeyValueStorage); super(null, bonsaiWorldStateKeyValueStorage);
} }
@ -33,7 +33,7 @@ public class NoOpCachedWorldStorageManager extends CachedWorldStorageManager {
public synchronized void addCachedLayer( public synchronized void addCachedLayer(
final BlockHeader blockHeader, final BlockHeader blockHeader,
final Hash worldStateRootHash, final Hash worldStateRootHash,
final BonsaiWorldState forWorldState) { final DiffBasedWorldState forWorldState) {
// no cache // no cache
} }
@ -43,17 +43,17 @@ public class NoOpCachedWorldStorageManager extends CachedWorldStorageManager {
} }
@Override @Override
public Optional<BonsaiWorldState> getWorldState(final Hash blockHash) { public Optional<DiffBasedWorldState> getWorldState(final Hash blockHash) {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public Optional<BonsaiWorldState> getNearestWorldState(final BlockHeader blockHeader) { public Optional<DiffBasedWorldState> getNearestWorldState(final BlockHeader blockHeader) {
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public Optional<BonsaiWorldState> getHeadWorldState( public Optional<DiffBasedWorldState> getHeadWorldState(
final Function<Hash, Optional<BlockHeader>> hashBlockHeaderFunction) { final Function<Hash, Optional<BlockHeader>> hashBlockHeaderFunction) {
return Optional.empty(); return Optional.empty();
} }

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;

@ -13,11 +13,12 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedSnapshotWorldStateKeyValueStorage;
import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SnappableKeyValueStorage;
@ -32,7 +33,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKeyValueStorage public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKeyValueStorage
implements BonsaiStorageSubscriber { implements DiffBasedSnapshotWorldStateKeyValueStorage, StorageSubscriber {
protected final BonsaiWorldStateKeyValueStorage parentWorldStateStorage; protected final BonsaiWorldStateKeyValueStorage parentWorldStateStorage;
private static final Logger LOG = private static final Logger LOG =
@ -53,9 +54,9 @@ public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKey
final BonsaiWorldStateKeyValueStorage worldStateStorageKeyValueStorage) { final BonsaiWorldStateKeyValueStorage worldStateStorageKeyValueStorage) {
this( this(
worldStateStorageKeyValueStorage, worldStateStorageKeyValueStorage,
((SnappableKeyValueStorage) worldStateStorageKeyValueStorage.composedWorldStateStorage) ((SnappableKeyValueStorage) worldStateStorageKeyValueStorage.getComposedWorldStateStorage())
.takeSnapshot(), .takeSnapshot(),
worldStateStorageKeyValueStorage.trieLogStorage); worldStateStorageKeyValueStorage.getTrieLogStorage());
} }
private boolean isClosedGet() { private boolean isClosedGet() {
@ -207,7 +208,7 @@ public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKey
protected synchronized void doClose() throws Exception { protected synchronized void doClose() throws Exception {
if (!isClosedGet()) { if (!isClosedGet()) {
// alert any subscribers we are closing: // alert any subscribers we are closing:
subscribers.forEach(BonsaiStorageSubscriber::onCloseStorage); subscribers.forEach(StorageSubscriber::onCloseStorage);
// close all of the SnappedKeyValueStorages: // close all of the SnappedKeyValueStorages:
composedWorldStateStorage.close(); composedWorldStateStorage.close();
@ -220,6 +221,7 @@ public class BonsaiSnapshotWorldStateKeyValueStorage extends BonsaiWorldStateKey
} }
} }
@Override
public BonsaiWorldStateKeyValueStorage getParentWorldStateStorage() { public BonsaiWorldStateKeyValueStorage getParentWorldStateStorage() {
return parentWorldStateStorage; return parentWorldStateStorage;
} }

@ -12,7 +12,7 @@
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE;
@ -24,8 +24,9 @@ import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.flat.FlatDbStrategy; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.flat.FlatDbStrategyProvider; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategyProvider;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
@ -37,52 +38,28 @@ import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
import org.hyperledger.besu.util.Subscribers;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.NavigableMap; import java.util.NavigableMap;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorage, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateKeyValueStorage.class);
// 0x776f726c64526f6f74
public static final byte[] WORLD_ROOT_HASH_KEY = "worldRoot".getBytes(StandardCharsets.UTF_8);
// 0x776f726c64426c6f636b48617368
public static final byte[] WORLD_BLOCK_HASH_KEY =
"worldBlockHash".getBytes(StandardCharsets.UTF_8);
public class BonsaiWorldStateKeyValueStorage extends DiffBasedWorldStateKeyValueStorage
implements WorldStateKeyValueStorage {
protected final FlatDbStrategyProvider flatDbStrategyProvider; protected final FlatDbStrategyProvider flatDbStrategyProvider;
protected final SegmentedKeyValueStorage composedWorldStateStorage;
protected final KeyValueStorage trieLogStorage;
private final AtomicBoolean shouldClose = new AtomicBoolean(false);
protected final AtomicBoolean isClosed = new AtomicBoolean(false);
protected final Subscribers<BonsaiStorageSubscriber> subscribers = Subscribers.create();
public BonsaiWorldStateKeyValueStorage( public BonsaiWorldStateKeyValueStorage(
final StorageProvider provider, final StorageProvider provider,
final MetricsSystem metricsSystem, final MetricsSystem metricsSystem,
final DataStorageConfiguration dataStorageConfiguration) { final DataStorageConfiguration dataStorageConfiguration) {
this.composedWorldStateStorage = super(
provider.getStorageBySegmentIdentifiers( provider.getStorageBySegmentIdentifiers(
List.of( List.of(
ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE)); ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE)),
this.trieLogStorage = provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE));
provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE);
this.flatDbStrategyProvider = this.flatDbStrategyProvider =
new FlatDbStrategyProvider(metricsSystem, dataStorageConfiguration); new FlatDbStrategyProvider(metricsSystem, dataStorageConfiguration);
flatDbStrategyProvider.loadFlatDbStrategy(composedWorldStateStorage); flatDbStrategyProvider.loadFlatDbStrategy(composedWorldStateStorage);
@ -92,9 +69,8 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
final FlatDbStrategyProvider flatDbStrategyProvider, final FlatDbStrategyProvider flatDbStrategyProvider,
final SegmentedKeyValueStorage composedWorldStateStorage, final SegmentedKeyValueStorage composedWorldStateStorage,
final KeyValueStorage trieLogStorage) { final KeyValueStorage trieLogStorage) {
super(composedWorldStateStorage, trieLogStorage);
this.flatDbStrategyProvider = flatDbStrategyProvider; this.flatDbStrategyProvider = flatDbStrategyProvider;
this.composedWorldStateStorage = composedWorldStateStorage;
this.trieLogStorage = trieLogStorage;
} }
@Override @Override
@ -102,6 +78,7 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
return DataStorageFormat.BONSAI; return DataStorageFormat.BONSAI;
} }
@Override
public FlatDbMode getFlatDbMode() { public FlatDbMode getFlatDbMode() {
return flatDbStrategyProvider.getFlatDbMode(); return flatDbStrategyProvider.getFlatDbMode();
} }
@ -155,31 +132,6 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
.map(Bytes::wrap); .map(Bytes::wrap);
} }
public Optional<byte[]> getTrieLog(final Hash blockHash) {
return trieLogStorage.get(blockHash.toArrayUnsafe());
}
public Stream<byte[]> streamTrieLogKeys(final long limit) {
return trieLogStorage.streamKeys().limit(limit);
}
public Optional<Bytes> getStateTrieNode(final Bytes location) {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe())
.map(Bytes::wrap);
}
public Optional<Bytes> getWorldStateRootHash() {
return composedWorldStateStorage.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY).map(Bytes::wrap);
}
public Optional<Hash> getWorldStateBlockHash() {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY)
.map(Bytes32::wrap)
.map(Hash::wrap);
}
public Optional<Bytes> getStorageValueByStorageSlotKey( public Optional<Bytes> getStorageValueByStorageSlotKey(
final Hash accountHash, final StorageSlotKey storageSlotKey) { final Hash accountHash, final StorageSlotKey storageSlotKey) {
return getStorageValueByStorageSlotKey( return getStorageValueByStorageSlotKey(
@ -209,34 +161,11 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
composedWorldStateStorage); composedWorldStateStorage);
} }
public Map<Bytes32, Bytes> streamFlatAccounts(
final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return flatDbStrategyProvider
.getFlatDbStrategy(composedWorldStateStorage)
.streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max);
}
public Map<Bytes32, Bytes> streamFlatStorages(
final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return flatDbStrategyProvider
.getFlatDbStrategy(composedWorldStateStorage)
.streamStorageFlatDatabase(
composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max);
}
public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom( public NavigableMap<Bytes32, AccountStorageEntry> storageEntriesFrom(
final Hash addressHash, final Bytes32 startKeyHash, final int limit) { final Hash addressHash, final Bytes32 startKeyHash, final int limit) {
throw new RuntimeException("Bonsai Tries does not currently support enumerating storage"); throw new RuntimeException("Bonsai Tries does not currently support enumerating storage");
} }
public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY)
.map(Bytes32::wrap)
.map(hash -> hash.equals(rootHash) || trieLogStorage.containsKey(blockHash.toArrayUnsafe()))
.orElse(false);
}
public void upgradeToFullFlatDbMode() { public void upgradeToFullFlatDbMode() {
flatDbStrategyProvider.upgradeToFullFlatDbMode(composedWorldStateStorage); flatDbStrategyProvider.upgradeToFullFlatDbMode(composedWorldStateStorage);
} }
@ -247,26 +176,14 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
@Override @Override
public void clear() { public void clear() {
subscribers.forEach(BonsaiStorageSubscriber::onClearStorage); super.clear();
flatDbStrategyProvider
.getFlatDbStrategy(composedWorldStateStorage)
.clearAll(composedWorldStateStorage);
composedWorldStateStorage.clear(TRIE_BRANCH_STORAGE);
trieLogStorage.clear();
flatDbStrategyProvider.loadFlatDbStrategy( flatDbStrategyProvider.loadFlatDbStrategy(
composedWorldStateStorage); // force reload of flat db reader strategy composedWorldStateStorage); // force reload of flat db reader strategy
} }
public void clearTrieLog() { @Override
subscribers.forEach(BonsaiStorageSubscriber::onClearTrieLog); public FlatDbStrategy getFlatDbStrategy() {
trieLogStorage.clear(); return flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage);
}
public void clearFlatDatabase() {
subscribers.forEach(BonsaiStorageSubscriber::onClearFlatDatabaseStorage);
flatDbStrategyProvider
.getFlatDbStrategy(composedWorldStateStorage)
.resetOnResync(composedWorldStateStorage);
} }
@Override @Override
@ -277,20 +194,7 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage)); flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage));
} }
public boolean pruneTrieLog(final Hash blockHash) { public static class Updater implements DiffBasedWorldStateKeyValueStorage.Updater {
try {
return trieLogStorage.tryDelete(blockHash.toArrayUnsafe());
} catch (Exception e) {
LOG.error("Error pruning trie log for block hash {}", blockHash, e);
return false;
}
}
public FlatDbStrategy getFlatDbStrategy() {
return flatDbStrategyProvider.getFlatDbStrategy(composedWorldStateStorage);
}
public static class Updater implements WorldStateKeyValueStorage.Updater {
private final SegmentedKeyValueStorageTransaction composedWorldStateTransaction; private final SegmentedKeyValueStorageTransaction composedWorldStateTransaction;
private final KeyValueStorageTransaction trieLogStorageTransaction; private final KeyValueStorageTransaction trieLogStorageTransaction;
@ -340,6 +244,7 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
return this; return this;
} }
@Override
public 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( composedWorldStateTransaction.put(
TRIE_BRANCH_STORAGE, Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe()); TRIE_BRANCH_STORAGE, Bytes.EMPTY.toArrayUnsafe(), node.toArrayUnsafe());
@ -392,10 +297,12 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
composedWorldStateTransaction, accountHash, slotHash); composedWorldStateTransaction, accountHash, slotHash);
} }
@Override
public SegmentedKeyValueStorageTransaction getWorldStateTransaction() { public SegmentedKeyValueStorageTransaction getWorldStateTransaction() {
return composedWorldStateTransaction; return composedWorldStateTransaction;
} }
@Override
public KeyValueStorageTransaction getTrieLogStorageTransaction() { public KeyValueStorageTransaction getTrieLogStorageTransaction() {
return trieLogStorageTransaction; return trieLogStorageTransaction;
} }
@ -407,65 +314,10 @@ public class BonsaiWorldStateKeyValueStorage implements WorldStateKeyValueStorag
composedWorldStateTransaction.commit(); composedWorldStateTransaction.commit();
} }
@Override
public void rollback() { public void rollback() {
composedWorldStateTransaction.rollback(); composedWorldStateTransaction.rollback();
trieLogStorageTransaction.rollback(); trieLogStorageTransaction.rollback();
} }
} }
@Override
public synchronized void close() throws Exception {
// when the storage clears, close
shouldClose.set(true);
tryClose();
}
public synchronized long subscribe(final BonsaiStorageSubscriber sub) {
if (isClosed.get()) {
throw new RuntimeException("Storage is marked to close or has already closed");
}
return subscribers.subscribe(sub);
}
public synchronized void unSubscribe(final long id) {
subscribers.unsubscribe(id);
try {
tryClose();
} catch (Exception e) {
LOG.atWarn()
.setMessage("exception while trying to close : {}")
.addArgument(e::getMessage)
.log();
}
}
protected synchronized void tryClose() throws Exception {
if (shouldClose.get() && subscribers.getSubscriberCount() < 1) {
doClose();
}
}
protected synchronized void doClose() throws Exception {
if (!isClosed.get()) {
// alert any subscribers we are closing:
subscribers.forEach(BonsaiStorageSubscriber::onCloseStorage);
// close all of the KeyValueStorages:
composedWorldStateStorage.close();
trieLogStorage.close();
// set storage closed
isClosed.set(true);
}
}
public interface BonsaiStorageSubscriber {
default void onClearStorage() {}
default void onClearFlatDatabaseStorage() {}
default void onClearTrieLog() {}
default void onCloseStorage() {}
}
} }

@ -13,21 +13,22 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedLayeredWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorage; import org.hyperledger.besu.plugin.services.storage.KeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SnappedKeyValueStorage;
import org.hyperledger.besu.services.kvstore.LayeredKeyValueStorage; import org.hyperledger.besu.services.kvstore.LayeredKeyValueStorage;
public class BonsaiWorldStateLayerStorage extends BonsaiSnapshotWorldStateKeyValueStorage public class BonsaiWorldStateLayerStorage extends BonsaiSnapshotWorldStateKeyValueStorage
implements BonsaiStorageSubscriber { implements DiffBasedLayeredWorldStateKeyValueStorage, StorageSubscriber {
public BonsaiWorldStateLayerStorage(final BonsaiWorldStateKeyValueStorage parent) { public BonsaiWorldStateLayerStorage(final BonsaiWorldStateKeyValueStorage parent) {
this( this(
new LayeredKeyValueStorage(parent.composedWorldStateStorage), new LayeredKeyValueStorage(parent.getComposedWorldStateStorage()),
parent.trieLogStorage, parent.getTrieLogStorage(),
parent); parent);
} }

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE;
@ -21,6 +21,8 @@ import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIden
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.ethereum.trie.NodeLoader;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.CodeStorageStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.metrics.Counter;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE;
@ -21,6 +21,8 @@ import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIden
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.ethereum.trie.NodeLoader;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.CodeStorageStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory; import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog;
import org.hyperledger.besu.datatypes.AccountValue; import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
@ -23,7 +23,8 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput; import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
@ -150,7 +151,7 @@ public class TrieLogFactoryImpl implements TrieLogFactory {
final TrieLogLayer newLayer = new TrieLogLayer(); final TrieLogLayer newLayer = new TrieLogLayer();
input.enterList(); input.enterList();
newLayer.blockHash = Hash.wrap(input.readBytes32()); newLayer.setBlockHash(Hash.wrap(input.readBytes32()));
while (!input.isEndOfCurrentList()) { while (!input.isEndOfCurrentList()) {
input.enterList(); input.enterList();
@ -164,7 +165,9 @@ public class TrieLogFactoryImpl implements TrieLogFactory {
final StateTrieAccountValue newValue = nullOrValue(input, StateTrieAccountValue::readFrom); final StateTrieAccountValue newValue = nullOrValue(input, StateTrieAccountValue::readFrom);
final boolean isCleared = getOptionalIsCleared(input); final boolean isCleared = getOptionalIsCleared(input);
input.leaveList(); input.leaveList();
newLayer.accounts.put(address, new BonsaiValue<>(oldValue, newValue, isCleared)); newLayer
.getAccountChanges()
.put(address, new DiffBasedValue<>(oldValue, newValue, isCleared));
} }
if (input.nextIsNull()) { if (input.nextIsNull()) {
@ -175,13 +178,13 @@ public class TrieLogFactoryImpl implements TrieLogFactory {
final Bytes newCode = nullOrValue(input, RLPInput::readBytes); final Bytes newCode = nullOrValue(input, RLPInput::readBytes);
final boolean isCleared = getOptionalIsCleared(input); final boolean isCleared = getOptionalIsCleared(input);
input.leaveList(); input.leaveList();
newLayer.code.put(address, new BonsaiValue<>(oldCode, newCode, isCleared)); newLayer.getCodeChanges().put(address, new DiffBasedValue<>(oldCode, newCode, isCleared));
} }
if (input.nextIsNull()) { if (input.nextIsNull()) {
input.skipNext(); input.skipNext();
} else { } else {
final Map<StorageSlotKey, BonsaiValue<UInt256>> storageChanges = new TreeMap<>(); final Map<StorageSlotKey, DiffBasedValue<UInt256>> storageChanges = new TreeMap<>();
input.enterList(); input.enterList();
while (!input.isEndOfCurrentList()) { while (!input.isEndOfCurrentList()) {
input.enterList(); input.enterList();
@ -190,11 +193,11 @@ public class TrieLogFactoryImpl implements TrieLogFactory {
final UInt256 oldValue = nullOrValue(input, RLPInput::readUInt256Scalar); final UInt256 oldValue = nullOrValue(input, RLPInput::readUInt256Scalar);
final UInt256 newValue = nullOrValue(input, RLPInput::readUInt256Scalar); final UInt256 newValue = nullOrValue(input, RLPInput::readUInt256Scalar);
final boolean isCleared = getOptionalIsCleared(input); final boolean isCleared = getOptionalIsCleared(input);
storageChanges.put(storageSlotKey, new BonsaiValue<>(oldValue, newValue, isCleared)); storageChanges.put(storageSlotKey, new DiffBasedValue<>(oldValue, newValue, isCleared));
input.leaveList(); input.leaveList();
} }
input.leaveList(); input.leaveList();
newLayer.storage.put(address, storageChanges); newLayer.getStorageChanges().put(address, storageChanges);
} }
// TODO add trie nodes // TODO add trie nodes

@ -14,39 +14,33 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.worldview; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import static org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY; import static org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView.encodeTrieValue;
import static org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY;
import static org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldView.encodeTrieValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.NodeLoader; import org.hyperledger.besu.ethereum.trie.NodeLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateLayerStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiSnapshotWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateLayerStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator.StorageConsumingMap; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.StorageConsumingMap;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier; import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
@ -63,24 +57,10 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.rlp.RLP; import org.apache.tuweni.rlp.RLP;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BonsaiWorldState public class BonsaiWorldState extends DiffBasedWorldState {
implements MutableWorldState, BonsaiWorldView, BonsaiStorageSubscriber {
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldState.class); protected final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader;
protected BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage;
protected final CachedMerkleTrieLoader cachedMerkleTrieLoader;
protected final CachedWorldStorageManager cachedWorldStorageManager;
protected final TrieLogManager trieLogManager;
private BonsaiWorldStateUpdateAccumulator accumulator;
protected Hash worldStateRootHash;
Hash worldStateBlockHash;
private boolean isFrozen;
public BonsaiWorldState( public BonsaiWorldState(
final BonsaiWorldStateProvider archive, final BonsaiWorldStateProvider archive,
@ -96,90 +76,39 @@ public class BonsaiWorldState
public BonsaiWorldState( public BonsaiWorldState(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final CachedMerkleTrieLoader cachedMerkleTrieLoader, final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader,
final CachedWorldStorageManager cachedWorldStorageManager, final DiffBasedCachedWorldStorageManager cachedWorldStorageManager,
final TrieLogManager trieLogManager, final TrieLogManager trieLogManager,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
this.worldStateKeyValueStorage = worldStateKeyValueStorage; super(worldStateKeyValueStorage, cachedWorldStorageManager, trieLogManager);
this.worldStateRootHash = this.bonsaiCachedMerkleTrieLoader = bonsaiCachedMerkleTrieLoader;
Hash.wrap( this.setAccumulator(
Bytes32.wrap(
worldStateKeyValueStorage.getWorldStateRootHash().orElse(getEmptyTrieHash())));
this.worldStateBlockHash =
Hash.wrap(
Bytes32.wrap(worldStateKeyValueStorage.getWorldStateBlockHash().orElse(Hash.ZERO)));
this.accumulator =
new BonsaiWorldStateUpdateAccumulator( new BonsaiWorldStateUpdateAccumulator(
this, this,
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadAccount( bonsaiCachedMerkleTrieLoader.preLoadAccount(
getWorldStateStorage(), worldStateRootHash, addr), worldStateKeyValueStorage, worldStateRootHash, addr),
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value), bonsaiCachedMerkleTrieLoader.preLoadStorageSlot(
evmConfiguration); getWorldStateStorage(), addr, value),
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; evmConfiguration));
this.cachedWorldStorageManager = cachedWorldStorageManager;
this.trieLogManager = trieLogManager;
}
/**
* Override the accumulator solves the chicken-egg problem of needing a worldstate reference
* (this) when construction the Accumulator.
*
* @param accumulator accumulator to use.
*/
public void setAccumulator(final BonsaiWorldStateUpdateAccumulator accumulator) {
this.accumulator = accumulator;
}
/**
* Returns the world state block hash of this world state
*
* @return the world state block hash.
*/
public Hash getWorldStateBlockHash() {
return worldStateBlockHash;
}
/**
* Returns the world state root hash of this world state
*
* @return the world state root hash.
*/
public Hash getWorldStateRootHash() {
return worldStateRootHash;
} }
@Override @Override
public boolean isPersisted() { public BonsaiWorldStateKeyValueStorage getWorldStateStorage() {
return isPersisted(worldStateKeyValueStorage); return (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage;
}
private boolean isPersisted(final WorldStateKeyValueStorage worldStateKeyValueStorage) {
return !(worldStateKeyValueStorage instanceof BonsaiSnapshotWorldStateKeyValueStorage);
}
@Override
public Optional<Bytes> getCode(@Nonnull final Address address, final Hash codeHash) {
return worldStateKeyValueStorage.getCode(codeHash, address.addressHash());
}
/**
* Reset the worldState to this block header
*
* @param blockHeader block to use
*/
public void resetWorldStateTo(final BlockHeader blockHeader) {
worldStateBlockHash = blockHeader.getBlockHash();
worldStateRootHash = blockHeader.getStateRoot();
} }
@Override @Override
public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { protected Hash calculateRootHash(
return worldStateKeyValueStorage; final Optional<DiffBasedWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final DiffBasedWorldStateUpdateAccumulator<?> worldStateUpdater) {
return internalCalculateRootHash(
maybeStateUpdater.map(BonsaiWorldStateKeyValueStorage.Updater.class::cast),
(BonsaiWorldStateUpdateAccumulator) worldStateUpdater);
} }
private Hash calculateRootHash( private Hash internalCalculateRootHash(
final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater, final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { final BonsaiWorldStateUpdateAccumulator worldStateUpdater) {
@ -187,7 +116,7 @@ public class BonsaiWorldState
// This must be done before updating the accounts so // This must be done before updating the accounts so
// that we can get the storage state hash // that we can get the storage state hash
Stream<Map.Entry<Address, StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>>>> Stream<Map.Entry<Address, StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>>>>
storageStream = worldStateUpdater.getStorageToUpdate().entrySet().stream(); storageStream = worldStateUpdater.getStorageToUpdate().entrySet().stream();
if (maybeStateUpdater.isEmpty()) { if (maybeStateUpdater.isEmpty()) {
storageStream = storageStream =
@ -205,8 +134,8 @@ public class BonsaiWorldState
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie = final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie =
createTrie( createTrie(
(location, hash) -> (location, hash) ->
cachedMerkleTrieLoader.getAccountStateTrieNode( bonsaiCachedMerkleTrieLoader.getAccountStateTrieNode(
worldStateKeyValueStorage, location, hash), getWorldStateStorage(), location, hash),
worldStateRootHash); worldStateRootHash);
// for manicured tries and composting, collect branches here (not implemented) // for manicured tries and composting, collect branches here (not implemented)
@ -231,10 +160,10 @@ public class BonsaiWorldState
final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater, final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final BonsaiWorldStateUpdateAccumulator worldStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater,
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie) { final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie) {
for (final Map.Entry<Address, BonsaiValue<BonsaiAccount>> accountUpdate : for (final Map.Entry<Address, DiffBasedValue<BonsaiAccount>> accountUpdate :
worldStateUpdater.getAccountsToUpdate().entrySet()) { worldStateUpdater.getAccountsToUpdate().entrySet()) {
final Bytes accountKey = accountUpdate.getKey(); final Bytes accountKey = accountUpdate.getKey();
final BonsaiValue<BonsaiAccount> bonsaiValue = accountUpdate.getValue(); final DiffBasedValue<BonsaiAccount> bonsaiValue = accountUpdate.getValue();
final BonsaiAccount updatedAccount = bonsaiValue.getUpdated(); final BonsaiAccount updatedAccount = bonsaiValue.getUpdated();
try { try {
if (updatedAccount == null) { if (updatedAccount == null) {
@ -264,7 +193,7 @@ public class BonsaiWorldState
final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { final BonsaiWorldStateUpdateAccumulator worldStateUpdater) {
maybeStateUpdater.ifPresent( maybeStateUpdater.ifPresent(
bonsaiUpdater -> { bonsaiUpdater -> {
for (final Map.Entry<Address, BonsaiValue<Bytes>> codeUpdate : for (final Map.Entry<Address, DiffBasedValue<Bytes>> codeUpdate :
worldStateUpdater.getCodeToUpdate().entrySet()) { worldStateUpdater.getCodeToUpdate().entrySet()) {
final Bytes updatedCode = codeUpdate.getValue().getUpdated(); final Bytes updatedCode = codeUpdate.getValue().getUpdated();
final Hash accountHash = codeUpdate.getKey().addressHash(); final Hash accountHash = codeUpdate.getKey().addressHash();
@ -294,12 +223,12 @@ public class BonsaiWorldState
private void updateAccountStorageState( private void updateAccountStorageState(
final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater, final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final BonsaiWorldStateUpdateAccumulator worldStateUpdater, final BonsaiWorldStateUpdateAccumulator worldStateUpdater,
final Map.Entry<Address, StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>>> final Map.Entry<Address, StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>>>
storageAccountUpdate) { storageAccountUpdate) {
final Address updatedAddress = storageAccountUpdate.getKey(); final Address updatedAddress = storageAccountUpdate.getKey();
final Hash updatedAddressHash = updatedAddress.addressHash(); final Hash updatedAddressHash = updatedAddress.addressHash();
if (worldStateUpdater.getAccountsToUpdate().containsKey(updatedAddress)) { if (worldStateUpdater.getAccountsToUpdate().containsKey(updatedAddress)) {
final BonsaiValue<BonsaiAccount> accountValue = final DiffBasedValue<BonsaiAccount> accountValue =
worldStateUpdater.getAccountsToUpdate().get(updatedAddress); worldStateUpdater.getAccountsToUpdate().get(updatedAddress);
final BonsaiAccount accountOriginal = accountValue.getPrior(); final BonsaiAccount accountOriginal = accountValue.getPrior();
final Hash storageRoot = final Hash storageRoot =
@ -310,12 +239,12 @@ public class BonsaiWorldState
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie = final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
createTrie( createTrie(
(location, key) -> (location, key) ->
cachedMerkleTrieLoader.getAccountStorageTrieNode( bonsaiCachedMerkleTrieLoader.getAccountStorageTrieNode(
worldStateKeyValueStorage, updatedAddressHash, location, key), getWorldStateStorage(), updatedAddressHash, location, key),
storageRoot); storageRoot);
// for manicured tries and composting, collect branches here (not implemented) // for manicured tries and composting, collect branches here (not implemented)
for (final Map.Entry<StorageSlotKey, BonsaiValue<UInt256>> storageUpdate : for (final Map.Entry<StorageSlotKey, DiffBasedValue<UInt256>> storageUpdate :
storageAccountUpdate.getValue().entrySet()) { storageAccountUpdate.getValue().entrySet()) {
final Hash slotHash = storageUpdate.getKey().getSlotHash(); final Hash slotHash = storageUpdate.getKey().getSlotHash();
final UInt256 updatedStorage = storageUpdate.getValue().getUpdated(); final UInt256 updatedStorage = storageUpdate.getValue().getUpdated();
@ -360,11 +289,10 @@ public class BonsaiWorldState
private void clearStorage( private void clearStorage(
final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater, final Optional<BonsaiWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final BonsaiWorldStateUpdateAccumulator worldStateUpdater) { final BonsaiWorldStateUpdateAccumulator worldStateUpdater) {
for (final Address address : worldStateUpdater.getStorageToClear()) { for (final Address address : worldStateUpdater.getStorageToClear()) {
// because we are clearing persisted values we need the account root as persisted // because we are clearing persisted values we need the account root as persisted
final BonsaiAccount oldAccount = final BonsaiAccount oldAccount =
worldStateKeyValueStorage getWorldStateStorage()
.getAccount(address.addressHash()) .getAccount(address.addressHash())
.map(bytes -> BonsaiAccount.fromRLP(BonsaiWorldState.this, address, bytes, true)) .map(bytes -> BonsaiAccount.fromRLP(BonsaiWorldState.this, address, bytes, true))
.orElse(null); .orElse(null);
@ -379,7 +307,7 @@ public class BonsaiWorldState
(location, key) -> getStorageTrieNode(addressHash, location, key), (location, key) -> getStorageTrieNode(addressHash, location, key),
oldAccount.getStorageRoot()); oldAccount.getStorageRoot());
try { try {
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> storageToDelete = final StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>> storageToDelete =
worldStateUpdater.getStorageToUpdate().get(address); worldStateUpdater.getStorageToUpdate().get(address);
Map<Bytes32, Bytes> entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256); Map<Bytes32, Bytes> entriesToDelete = storageTrie.entriesFrom(Bytes32.ZERO, 256);
while (!entriesToDelete.isEmpty()) { while (!entriesToDelete.isEmpty()) {
@ -394,7 +322,7 @@ public class BonsaiWorldState
address.addressHash(), storageSlotKey.getSlotHash())); address.addressHash(), storageSlotKey.getSlotHash()));
storageToDelete storageToDelete
.computeIfAbsent( .computeIfAbsent(
storageSlotKey, key -> new BonsaiValue<>(slotValue, null, true)) storageSlotKey, key -> new DiffBasedValue<>(slotValue, null, true))
.setPrior(slotValue); .setPrior(slotValue);
}); });
entriesToDelete.keySet().forEach(storageTrie::remove); entriesToDelete.keySet().forEach(storageTrie::remove);
@ -412,138 +340,6 @@ public class BonsaiWorldState
} }
} }
@Override
public void persist(final BlockHeader blockHeader) {
final Optional<BlockHeader> maybeBlockHeader = Optional.ofNullable(blockHeader);
LOG.atDebug()
.setMessage("Persist world state for block {}")
.addArgument(maybeBlockHeader)
.log();
final BonsaiWorldStateUpdateAccumulator localCopy = accumulator.copy();
boolean success = false;
final BonsaiWorldStateKeyValueStorage.Updater stateUpdater =
worldStateKeyValueStorage.updater();
Runnable saveTrieLog = () -> {};
try {
final Hash newWorldStateRootHash =
calculateRootHash(isFrozen ? Optional.empty() : Optional.of(stateUpdater), accumulator);
// if we are persisted with a block header, and the prior state is the parent
// then persist the TrieLog for that transition.
// If specified but not a direct descendant simply store the new block hash.
if (blockHeader != null) {
verifyWorldStateRoot(newWorldStateRootHash, blockHeader);
saveTrieLog =
() -> {
trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this);
// not save a frozen state in the cache
if (!isFrozen) {
cachedWorldStorageManager.addCachedLayer(blockHeader, newWorldStateRootHash, this);
}
};
stateUpdater
.getWorldStateTransaction()
.put(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe());
worldStateBlockHash = blockHeader.getHash();
} else {
stateUpdater.getWorldStateTransaction().remove(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY);
worldStateBlockHash = null;
}
stateUpdater
.getWorldStateTransaction()
.put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, newWorldStateRootHash.toArrayUnsafe());
worldStateRootHash = newWorldStateRootHash;
success = true;
} finally {
if (success) {
stateUpdater.commit();
accumulator.reset();
saveTrieLog.run();
} else {
stateUpdater.rollback();
accumulator.reset();
}
}
}
protected void verifyWorldStateRoot(final Hash calculatedStateRoot, final BlockHeader header) {
if (!calculatedStateRoot.equals(header.getStateRoot())) {
throw new RuntimeException(
"World State Root does not match expected value, header "
+ header.getStateRoot().toHexString()
+ " calculated "
+ calculatedStateRoot.toHexString());
}
}
@Override
public WorldUpdater updater() {
return accumulator;
}
@Override
public Hash rootHash() {
if (isFrozen && accumulator.isAccumulatorStateChanged()) {
worldStateRootHash = calculateRootHash(Optional.empty(), accumulator.copy());
accumulator.resetAccumulatorStateChanged();
}
return Hash.wrap(worldStateRootHash);
}
static final KeyValueStorageTransaction noOpTx =
new KeyValueStorageTransaction() {
@Override
public void put(final byte[] key, final byte[] value) {
// no-op
}
@Override
public void remove(final byte[] key) {
// no-op
}
@Override
public void commit() throws StorageException {
// no-op
}
@Override
public void rollback() {
// no-op
}
};
static final SegmentedKeyValueStorageTransaction noOpSegmentedTx =
new SegmentedKeyValueStorageTransaction() {
@Override
public void put(
final SegmentIdentifier segmentIdentifier, final byte[] key, final byte[] value) {
// no-op
}
@Override
public void remove(final SegmentIdentifier segmentIdentifier, final byte[] key) {
// no-op
}
@Override
public void commit() throws StorageException {
// no-op
}
@Override
public void rollback() {
// no-op
}
};
@Override @Override
public Hash frontierRootHash() { public Hash frontierRootHash() {
return calculateRootHash( return calculateRootHash(
@ -553,25 +349,28 @@ public class BonsaiWorldState
accumulator.copy()); accumulator.copy());
} }
public Hash blockHash() {
return worldStateBlockHash;
}
@Override @Override
public Stream<StreamableAccount> streamAccounts(final Bytes32 startKeyHash, final int limit) { public MutableWorldState freeze() {
throw new RuntimeException("Bonsai Tries do not provide account streaming."); this.isFrozen = true;
this.worldStateKeyValueStorage = new BonsaiWorldStateLayerStorage(getWorldStateStorage());
return this;
} }
@Override @Override
public Account get(final Address address) { public Account get(final Address address) {
return worldStateKeyValueStorage return getWorldStateStorage()
.getAccount(address.addressHash()) .getAccount(address.addressHash())
.map(bytes -> BonsaiAccount.fromRLP(accumulator, address, bytes, true)) .map(bytes -> BonsaiAccount.fromRLP(accumulator, address, bytes, true))
.orElse(null); .orElse(null);
} }
@Override
public Optional<Bytes> getCode(@Nonnull final Address address, final Hash codeHash) {
return getWorldStateStorage().getCode(codeHash, address.addressHash());
}
protected Optional<Bytes> getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) { protected Optional<Bytes> getAccountStateTrieNode(final Bytes location, final Bytes32 nodeHash) {
return worldStateKeyValueStorage.getAccountStateTrieNode(location, nodeHash); return getWorldStateStorage().getAccountStateTrieNode(location, nodeHash);
} }
private void writeTrieNode( private void writeTrieNode(
@ -584,7 +383,7 @@ public class BonsaiWorldState
protected Optional<Bytes> getStorageTrieNode( protected Optional<Bytes> getStorageTrieNode(
final Hash accountHash, final Bytes location, final Bytes32 nodeHash) { final Hash accountHash, final Bytes location, final Bytes32 nodeHash) {
return worldStateKeyValueStorage.getAccountStorageTrieNode(accountHash, location, nodeHash); return getWorldStateStorage().getAccountStorageTrieNode(accountHash, location, nodeHash);
} }
private void writeStorageTrieNode( private void writeStorageTrieNode(
@ -605,7 +404,7 @@ public class BonsaiWorldState
@Override @Override
public Optional<UInt256> getStorageValueByStorageSlotKey( public Optional<UInt256> getStorageValueByStorageSlotKey(
final Address address, final StorageSlotKey storageSlotKey) { final Address address, final StorageSlotKey storageSlotKey) {
return worldStateKeyValueStorage return getWorldStateStorage()
.getStorageValueByStorageSlotKey(address.addressHash(), storageSlotKey) .getStorageValueByStorageSlotKey(address.addressHash(), storageSlotKey)
.map(UInt256::fromBytes); .map(UInt256::fromBytes);
} }
@ -614,7 +413,7 @@ public class BonsaiWorldState
final Supplier<Optional<Hash>> storageRootSupplier, final Supplier<Optional<Hash>> storageRootSupplier,
final Address address, final Address address,
final StorageSlotKey storageSlotKey) { final StorageSlotKey storageSlotKey) {
return worldStateKeyValueStorage return getWorldStateStorage()
.getStorageValueByStorageSlotKey(storageRootSupplier, address.addressHash(), storageSlotKey) .getStorageValueByStorageSlotKey(storageRootSupplier, address.addressHash(), storageSlotKey)
.map(UInt256::fromBytes); .map(UInt256::fromBytes);
} }
@ -632,50 +431,18 @@ public class BonsaiWorldState
return storageTrie.entriesFrom(Bytes32.ZERO, Integer.MAX_VALUE); return storageTrie.entriesFrom(Bytes32.ZERO, Integer.MAX_VALUE);
} }
@Override
public MutableWorldState freeze() {
this.isFrozen = true;
this.worldStateKeyValueStorage = new BonsaiWorldStateLayerStorage(worldStateKeyValueStorage);
return this;
}
private StoredMerklePatriciaTrie<Bytes, Bytes> createTrie( private StoredMerklePatriciaTrie<Bytes, Bytes> createTrie(
final NodeLoader nodeLoader, final Bytes32 rootHash) { final NodeLoader nodeLoader, final Bytes32 rootHash) {
return new StoredMerklePatriciaTrie<>( return new StoredMerklePatriciaTrie<>(
nodeLoader, rootHash, Function.identity(), Function.identity()); nodeLoader, rootHash, Function.identity(), Function.identity());
} }
@Override
public void close() {
try {
if (!isPersisted()) {
this.worldStateKeyValueStorage.close();
if (isFrozen) {
closeFrozenStorage();
}
}
} catch (Exception e) {
// no op
}
}
private void closeFrozenStorage() {
try {
final BonsaiWorldStateLayerStorage worldStateLayerStorage =
(BonsaiWorldStateLayerStorage) worldStateKeyValueStorage;
if (!isPersisted(worldStateLayerStorage.getParentWorldStateStorage())) {
worldStateLayerStorage.getParentWorldStateStorage().close();
}
} catch (Exception e) {
// no op
}
}
protected Hash hashAndSavePreImage(final Bytes value) { protected Hash hashAndSavePreImage(final Bytes value) {
// by default do not save has preImages // by default do not save has preImages
return Hash.hash(value); return Hash.hash(value);
} }
@Override
protected Hash getEmptyTrieHash() { protected Hash getEmptyTrieHash() {
return Hash.EMPTY_TRIE_HASH; return Hash.EMPTY_TRIE_HASH;
} }

@ -0,0 +1,98 @@
/*
* 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.trie.diffbased.bonsai.worldview;
import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.Consumer;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.worldstate.UpdateTrackingAccount;
public class BonsaiWorldStateUpdateAccumulator
extends DiffBasedWorldStateUpdateAccumulator<BonsaiAccount> {
public BonsaiWorldStateUpdateAccumulator(
final DiffBasedWorldView world,
final Consumer<DiffBasedValue<BonsaiAccount>> accountPreloader,
final Consumer<StorageSlotKey> storagePreloader,
final EvmConfiguration evmConfiguration) {
super(world, accountPreloader, storagePreloader, evmConfiguration);
}
@Override
public DiffBasedWorldStateUpdateAccumulator<BonsaiAccount> copy() {
final BonsaiWorldStateUpdateAccumulator copy =
new BonsaiWorldStateUpdateAccumulator(
wrappedWorldView(),
getAccountPreloader(),
getStoragePreloader(),
getEvmConfiguration());
copy.cloneFromUpdater(this);
return copy;
}
@Override
protected BonsaiAccount copyAccount(final BonsaiAccount account) {
return new BonsaiAccount(account);
}
@Override
protected BonsaiAccount copyAccount(
final BonsaiAccount toCopy, final DiffBasedWorldView context, final boolean mutable) {
return new BonsaiAccount(toCopy, context, mutable);
}
@Override
protected BonsaiAccount createAccount(
final DiffBasedWorldView context,
final Address address,
final AccountValue stateTrieAccount,
final boolean mutable) {
return new BonsaiAccount(context, address, stateTrieAccount, mutable);
}
@Override
protected BonsaiAccount createAccount(
final DiffBasedWorldView context,
final Address address,
final Hash addressHash,
final long nonce,
final Wei balance,
final Hash storageRoot,
final Hash codeHash,
final boolean mutable) {
return new BonsaiAccount(
context, address, addressHash, nonce, balance, storageRoot, codeHash, mutable);
}
@Override
protected BonsaiAccount createAccount(
final DiffBasedWorldView context, final UpdateTrackingAccount<BonsaiAccount> tracked) {
return new BonsaiAccount(context, tracked);
}
@Override
protected void assertCloseEnoughForDiffing(
final BonsaiAccount source, final AccountValue account, final String context) {
BonsaiAccount.assertCloseEnoughForDiffing(source, account, context);
}
}

@ -0,0 +1,206 @@
/*
* 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.trie.diffbased.common;
import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.evm.ModificationNotAllowedException;
import org.hyperledger.besu.evm.account.MutableAccount;
import java.util.HashMap;
import java.util.Map;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
public abstract class DiffBasedAccount implements MutableAccount, AccountValue {
protected final DiffBasedWorldView context;
protected boolean immutable;
protected final Address address;
protected final Hash addressHash;
protected Hash codeHash;
protected long nonce;
protected Wei balance;
protected Bytes code;
protected final Map<UInt256, UInt256> updatedStorage = new HashMap<>();
public DiffBasedAccount(
final DiffBasedWorldView context,
final Address address,
final Hash addressHash,
final long nonce,
final Wei balance,
final Hash codeHash,
final boolean mutable) {
this.context = context;
this.address = address;
this.addressHash = addressHash;
this.nonce = nonce;
this.balance = balance;
this.codeHash = codeHash;
this.immutable = !mutable;
}
public DiffBasedAccount(
final DiffBasedWorldView context,
final Address address,
final AccountValue stateTrieAccount,
final boolean mutable) {
this(
context,
address,
address.addressHash(),
stateTrieAccount.getNonce(),
stateTrieAccount.getBalance(),
stateTrieAccount.getCodeHash(),
mutable);
}
public DiffBasedAccount(
final DiffBasedAccount toCopy, final DiffBasedWorldView context, final boolean mutable) {
this.context = context;
this.address = toCopy.address;
this.addressHash = toCopy.addressHash;
this.nonce = toCopy.nonce;
this.balance = toCopy.balance;
this.codeHash = toCopy.codeHash;
this.code = toCopy.code;
updatedStorage.putAll(toCopy.updatedStorage);
this.immutable = !mutable;
}
@Override
public Address getAddress() {
return address;
}
@Override
public Hash getAddressHash() {
return addressHash;
}
@Override
public long getNonce() {
return nonce;
}
@Override
public void setNonce(final long value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
nonce = value;
}
@Override
public Wei getBalance() {
return balance;
}
@Override
public void setBalance(final Wei value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
balance = value;
}
@Override
public Bytes getCode() {
if (code == null) {
code = context.getCode(address, codeHash).orElse(Bytes.EMPTY);
}
return code;
}
@Override
public void setCode(final Bytes code) {
if (immutable) {
throw new ModificationNotAllowedException();
}
this.code = code;
if (code == null || code.isEmpty()) {
this.codeHash = Hash.EMPTY;
} else {
this.codeHash = Hash.hash(code);
}
}
@Override
public Hash getCodeHash() {
return codeHash;
}
@Override
public UInt256 getStorageValue(final UInt256 key) {
return context.getStorageValue(address, key);
}
@Override
public UInt256 getOriginalStorageValue(final UInt256 key) {
return context.getPriorStorageValue(address, key);
}
public Bytes serializeAccount() {
final BytesValueRLPOutput out = new BytesValueRLPOutput();
writeTo(out);
return out.encoded();
}
@Override
public void setStorageValue(final UInt256 key, final UInt256 value) {
if (immutable) {
throw new ModificationNotAllowedException();
}
updatedStorage.put(key, value);
}
@Override
public void clearStorage() {
updatedStorage.clear();
}
@Override
public Map<UInt256, UInt256> getUpdatedStorage() {
return updatedStorage;
}
@Override
public void becomeImmutable() {
immutable = true;
}
@Override
public String toString() {
return "AccountState{"
+ "address="
+ address
+ ", nonce="
+ nonce
+ ", balance="
+ balance
+ ", codeHash="
+ codeHash
+ '}';
}
}

@ -1,5 +1,5 @@
/* /*
* Copyright ConsenSys AG. * Copyright Hyperledger Besu Contributors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * 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 * the License. You may obtain a copy of the License at
@ -11,38 +11,37 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.common;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder;
public class BonsaiValue<T> implements TrieLog.LogTuple<T> { public class DiffBasedValue<T> implements TrieLog.LogTuple<T> {
private T prior; private T prior;
private T updated; private T updated;
private boolean lastStepCleared; private boolean lastStepCleared;
private boolean clearedAtLeastOnce; private boolean clearedAtLeastOnce;
public BonsaiValue(final T prior, final T updated) { public DiffBasedValue(final T prior, final T updated) {
this.prior = prior; this.prior = prior;
this.updated = updated; this.updated = updated;
this.lastStepCleared = false; this.lastStepCleared = false;
this.clearedAtLeastOnce = false; this.clearedAtLeastOnce = false;
} }
public BonsaiValue(final T prior, final T updated, final boolean lastStepCleared) { public DiffBasedValue(final T prior, final T updated, final boolean lastStepCleared) {
this.prior = prior; this.prior = prior;
this.updated = updated; this.updated = updated;
this.lastStepCleared = lastStepCleared; this.lastStepCleared = lastStepCleared;
this.clearedAtLeastOnce = lastStepCleared; this.clearedAtLeastOnce = lastStepCleared;
} }
public BonsaiValue( public DiffBasedValue(
final T prior, final T prior,
final T updated, final T updated,
final boolean lastStepCleared, final boolean lastStepCleared,
@ -63,12 +62,12 @@ public class BonsaiValue<T> implements TrieLog.LogTuple<T> {
return updated; return updated;
} }
public BonsaiValue<T> setPrior(final T prior) { public DiffBasedValue<T> setPrior(final T prior) {
this.prior = prior; this.prior = prior;
return this; return this;
} }
public BonsaiValue<T> setUpdated(final T updated) { public DiffBasedValue<T> setUpdated(final T updated) {
this.lastStepCleared = updated == null; this.lastStepCleared = updated == null;
if (lastStepCleared) { if (lastStepCleared) {
this.clearedAtLeastOnce = true; this.clearedAtLeastOnce = true;
@ -94,7 +93,7 @@ public class BonsaiValue<T> implements TrieLog.LogTuple<T> {
@Override @Override
public String toString() { public String toString() {
return "BonsaiValue{" return "DiffBasedValue{"
+ "prior=" + "prior="
+ prior + prior
+ ", updated=" + ", updated="
@ -112,7 +111,7 @@ public class BonsaiValue<T> implements TrieLog.LogTuple<T> {
if (o == null || getClass() != o.getClass()) { if (o == null || getClass() != o.getClass()) {
return false; return false;
} }
BonsaiValue<?> that = (BonsaiValue<?>) o; DiffBasedValue<?> that = (DiffBasedValue<?>) o;
return new EqualsBuilder() return new EqualsBuilder()
.append(lastStepCleared, that.lastStepCleared) .append(lastStepCleared, that.lastStepCleared)
.append(prior, that.prior) .append(prior, that.prior)
@ -129,7 +128,7 @@ public class BonsaiValue<T> implements TrieLog.LogTuple<T> {
.toHashCode(); .toHashCode();
} }
public BonsaiValue<T> copy() { public DiffBasedValue<T> copy() {
return new BonsaiValue<T>(prior, updated, lastStepCleared, clearedAtLeastOnce); return new DiffBasedValue<T>(prior, updated, lastStepCleared, clearedAtLeastOnce);
} }
} }

@ -14,9 +14,7 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.common;
import static org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedWorldStorageManager.RETAINED_LAYERS;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
@ -25,91 +23,75 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.proof.WorldStateProof; import org.hyperledger.besu.ethereum.proof.WorldStateProof;
import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider; import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
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.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; 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.evm.worldstate.WorldState;
import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class BonsaiWorldStateProvider implements WorldStateArchive { public abstract class DiffBasedWorldStateProvider implements WorldStateArchive {
private static final Logger LOG = LoggerFactory.getLogger(DiffBasedWorldStateProvider.class);
private static final Logger LOG = LoggerFactory.getLogger(BonsaiWorldStateProvider.class); protected final Blockchain blockchain;
private final Blockchain blockchain; protected final TrieLogManager trieLogManager;
protected DiffBasedCachedWorldStorageManager cachedWorldStorageManager;
protected DiffBasedWorldState persistedState;
private final CachedWorldStorageManager cachedWorldStorageManager; protected final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage;
private final TrieLogManager trieLogManager;
private final BonsaiWorldState persistedState;
private final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage;
private final CachedMerkleTrieLoader cachedMerkleTrieLoader;
public BonsaiWorldStateProvider( public DiffBasedWorldStateProvider(
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final Blockchain blockchain, final Blockchain blockchain,
final Optional<Long> maxLayersToLoad, final Optional<Long> maxLayersToLoad,
final CachedMerkleTrieLoader cachedMerkleTrieLoader, final BesuContext pluginContext) {
final BesuContext pluginContext,
final EvmConfiguration evmConfiguration) {
this.worldStateKeyValueStorage = worldStateKeyValueStorage; this.worldStateKeyValueStorage = worldStateKeyValueStorage;
this.cachedWorldStorageManager = new CachedWorldStorageManager(this, worldStateKeyValueStorage);
// TODO: de-dup constructors // TODO: de-dup constructors
this.trieLogManager = this.trieLogManager =
new TrieLogManager( new TrieLogManager(
blockchain, blockchain,
worldStateKeyValueStorage, worldStateKeyValueStorage,
maxLayersToLoad.orElse(RETAINED_LAYERS), maxLayersToLoad.orElse(DiffBasedCachedWorldStorageManager.RETAINED_LAYERS),
pluginContext); pluginContext);
this.blockchain = blockchain; this.blockchain = blockchain;
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader;
this.persistedState = new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration);
blockchain
.getBlockHeader(persistedState.getWorldStateBlockHash())
.ifPresent(
blockHeader ->
this.cachedWorldStorageManager.addCachedLayer(
blockHeader, persistedState.getWorldStateRootHash(), persistedState));
} }
@VisibleForTesting public DiffBasedWorldStateProvider(
BonsaiWorldStateProvider( final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final CachedWorldStorageManager cachedWorldStorageManager,
final TrieLogManager trieLogManager,
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage,
final Blockchain blockchain, final Blockchain blockchain,
final CachedMerkleTrieLoader cachedMerkleTrieLoader, final TrieLogManager trieLogManager) {
final EvmConfiguration evmConfiguration) {
this.cachedWorldStorageManager = cachedWorldStorageManager; this.worldStateKeyValueStorage = worldStateKeyValueStorage;
// TODO: de-dup constructors
this.trieLogManager = trieLogManager; this.trieLogManager = trieLogManager;
this.blockchain = blockchain; this.blockchain = blockchain;
this.worldStateKeyValueStorage = worldStateKeyValueStorage; }
this.persistedState = new BonsaiWorldState(this, worldStateKeyValueStorage, evmConfiguration);
this.cachedMerkleTrieLoader = cachedMerkleTrieLoader; protected void provideCachedWorldStorageManager(
final DiffBasedCachedWorldStorageManager cachedWorldStorageManager) {
this.cachedWorldStorageManager = cachedWorldStorageManager;
}
protected void loadPersistedState(final DiffBasedWorldState persistedState) {
this.persistedState = persistedState;
blockchain blockchain
.getBlockHeader(persistedState.getWorldStateBlockHash()) .getBlockHeader(persistedState.getWorldStateBlockHash())
.ifPresent( .ifPresent(
@ -158,9 +140,7 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
.getWorldState(blockHeader.getHash()) .getWorldState(blockHeader.getHash())
.or(() -> cachedWorldStorageManager.getNearestWorldState(blockHeader)) .or(() -> cachedWorldStorageManager.getNearestWorldState(blockHeader))
.or(() -> cachedWorldStorageManager.getHeadWorldState(blockchain::getBlockHeader)) .or(() -> cachedWorldStorageManager.getHeadWorldState(blockchain::getBlockHeader))
.flatMap( .flatMap(worldState -> rollMutableStateToBlockHash(worldState, blockHeader.getHash()))
bonsaiWorldState ->
rollMutableStateToBlockHash(bonsaiWorldState, blockHeader.getHash()))
.map(MutableWorldState::freeze); .map(MutableWorldState::freeze);
} }
} }
@ -172,7 +152,7 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
} }
Optional<MutableWorldState> rollMutableStateToBlockHash( Optional<MutableWorldState> rollMutableStateToBlockHash(
final BonsaiWorldState mutableState, final Hash blockHash) { final DiffBasedWorldState mutableState, final Hash blockHash) {
if (blockHash.equals(mutableState.blockHash())) { if (blockHash.equals(mutableState.blockHash())) {
return Optional.of(mutableState); return Optional.of(mutableState);
} else { } else {
@ -221,19 +201,19 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
} }
// attempt the state rolling // attempt the state rolling
final BonsaiWorldStateUpdateAccumulator bonsaiUpdater = final DiffBasedWorldStateUpdateAccumulator<?> diffBasedUpdater =
(BonsaiWorldStateUpdateAccumulator) mutableState.updater(); (DiffBasedWorldStateUpdateAccumulator<?>) mutableState.updater();
try { try {
for (final TrieLog rollBack : rollBacks) { for (final TrieLog rollBack : rollBacks) {
LOG.debug("Attempting Rollback of {}", rollBack.getBlockHash()); LOG.debug("Attempting Rollback of {}", rollBack.getBlockHash());
bonsaiUpdater.rollBack(rollBack); diffBasedUpdater.rollBack(rollBack);
} }
for (int i = rollForwards.size() - 1; i >= 0; i--) { for (int i = rollForwards.size() - 1; i >= 0; i--) {
final var forward = rollForwards.get(i); final var forward = rollForwards.get(i);
LOG.debug("Attempting Rollforward of {}", rollForwards.get(i).getBlockHash()); LOG.debug("Attempting Rollforward of {}", rollForwards.get(i).getBlockHash());
bonsaiUpdater.rollForward(forward); diffBasedUpdater.rollForward(forward);
} }
bonsaiUpdater.commit(); diffBasedUpdater.commit();
mutableState.persist(blockchain.getBlockHeader(blockHash).get()); mutableState.persist(blockchain.getBlockHeader(blockHash).get());
@ -247,7 +227,7 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
throw re; throw re;
} catch (final Exception e) { } catch (final Exception e) {
// if we fail we must clean up the updater // if we fail we must clean up the updater
bonsaiUpdater.reset(); diffBasedUpdater.reset();
LOG.debug( LOG.debug(
"State rolling failed on " "State rolling failed on "
+ mutableState.getWorldStateStorage().getClass().getSimpleName() + mutableState.getWorldStateStorage().getClass().getSimpleName()
@ -269,80 +249,16 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
} }
} }
public CachedMerkleTrieLoader getCachedMerkleTrieLoader() {
return cachedMerkleTrieLoader;
}
@Override @Override
public MutableWorldState getMutable() { public MutableWorldState getMutable() {
return persistedState; return persistedState;
} }
/**
* Prepares the state healing process for a given address and location. It prepares the state
* healing, including retrieving data from storage, identifying invalid slots or nodes, removing
* account and slot from the state trie, and committing the changes. Finally, it downgrades the
* world state storage to partial flat database mode.
*/
public void prepareStateHealing(final Address address, final Bytes location) {
final Set<Bytes> keysToDelete = new HashSet<>();
final BonsaiWorldStateKeyValueStorage.Updater updater = worldStateKeyValueStorage.updater();
final Hash accountHash = address.addressHash();
final StoredMerklePatriciaTrie<Bytes, Bytes> accountTrie =
new StoredMerklePatriciaTrie<>(
(l, h) -> {
final Optional<Bytes> node = worldStateKeyValueStorage.getAccountStateTrieNode(l, h);
if (node.isPresent()) {
keysToDelete.add(l);
}
return node;
},
persistedState.getWorldStateRootHash(),
Function.identity(),
Function.identity());
try {
accountTrie
.get(accountHash)
.map(RLP::input)
.map(StateTrieAccountValue::readFrom)
.ifPresent(
account -> {
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
(l, h) -> {
Optional<Bytes> node =
worldStateKeyValueStorage.getAccountStorageTrieNode(
accountHash, l, h);
if (node.isPresent()) {
keysToDelete.add(Bytes.concatenate(accountHash, l));
}
return node;
},
account.getStorageRoot(),
Function.identity(),
Function.identity());
try {
storageTrie.getPath(location);
} catch (Exception eA) {
LOG.warn("Invalid slot found for account {} at location {}", address, location);
// ignore
}
});
} catch (Exception eA) {
LOG.warn("Invalid node for account {} at location {}", address, location);
// ignore
}
keysToDelete.forEach(bytes -> updater.removeAccountStateTrieNode(bytes));
updater.commit();
worldStateKeyValueStorage.downgradeToPartialFlatDbMode();
}
public TrieLogManager getTrieLogManager() { public TrieLogManager getTrieLogManager() {
return trieLogManager; return trieLogManager;
} }
public CachedWorldStorageManager getCachedWorldStorageManager() { public DiffBasedCachedWorldStorageManager getCachedWorldStorageManager() {
return cachedWorldStorageManager; return cachedWorldStorageManager;
} }
@ -360,7 +276,8 @@ public class BonsaiWorldStateProvider implements WorldStateArchive {
final Address accountAddress, final Address accountAddress,
final List<UInt256> accountStorageKeys, final List<UInt256> accountStorageKeys,
final Function<Optional<WorldStateProof>, ? extends Optional<U>> mapper) { final Function<Optional<WorldStateProof>, ? extends Optional<U>> mapper) {
try (BonsaiWorldState ws = (BonsaiWorldState) getMutable(blockHeader, false).orElse(null)) { try (DiffBasedWorldState ws =
(DiffBasedWorldState) getMutable(blockHeader, false).orElse(null)) {
if (ws != null) { if (ws != null) {
final WorldStateProofProvider worldStateProofProvider = final WorldStateProofProvider worldStateProofProvider =
new WorldStateProofProvider( new WorldStateProofProvider(

@ -0,0 +1,25 @@
/*
* 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.trie.diffbased.common;
public interface StorageSubscriber {
default void onClearStorage() {}
default void onClearFlatDatabaseStorage() {}
default void onClearTrieLog() {}
default void onCloseStorage() {}
}

@ -12,15 +12,15 @@
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.common.cache;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiSnapshotWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedLayeredWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateLayerStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.util.ArrayList; import java.util.ArrayList;
@ -35,20 +35,20 @@ import org.apache.tuweni.bytes.Bytes32;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CachedWorldStorageManager public abstract class DiffBasedCachedWorldStorageManager implements StorageSubscriber {
implements BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber {
public static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks public static final long RETAINED_LAYERS = 512; // at least 256 + typical rollbacks
private static final Logger LOG = LoggerFactory.getLogger(CachedWorldStorageManager.class); private static final Logger LOG =
private final BonsaiWorldStateProvider archive; LoggerFactory.getLogger(DiffBasedCachedWorldStorageManager.class);
private final DiffBasedWorldStateProvider archive;
private final EvmConfiguration evmConfiguration; private final EvmConfiguration evmConfiguration;
private final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; private final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage;
private final Map<Bytes32, CachedBonsaiWorldView> cachedWorldStatesByHash; private final Map<Bytes32, DiffBasedCachedWorldView> cachedWorldStatesByHash;
private CachedWorldStorageManager( private DiffBasedCachedWorldStorageManager(
final BonsaiWorldStateProvider archive, final DiffBasedWorldStateProvider archive,
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final Map<Bytes32, CachedBonsaiWorldView> cachedWorldStatesByHash, final Map<Bytes32, DiffBasedCachedWorldView> cachedWorldStatesByHash,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
worldStateKeyValueStorage.subscribe(this); worldStateKeyValueStorage.subscribe(this);
this.rootWorldStateStorage = worldStateKeyValueStorage; this.rootWorldStateStorage = worldStateKeyValueStorage;
@ -57,32 +57,32 @@ public class CachedWorldStorageManager
this.evmConfiguration = evmConfiguration; this.evmConfiguration = evmConfiguration;
} }
public CachedWorldStorageManager( public DiffBasedCachedWorldStorageManager(
final BonsaiWorldStateProvider archive, final DiffBasedWorldStateProvider archive,
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage) { final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage) {
this(archive, worldStateKeyValueStorage, new ConcurrentHashMap<>(), EvmConfiguration.DEFAULT); this(archive, worldStateKeyValueStorage, new ConcurrentHashMap<>(), EvmConfiguration.DEFAULT);
} }
public synchronized void addCachedLayer( public synchronized void addCachedLayer(
final BlockHeader blockHeader, final BlockHeader blockHeader,
final Hash worldStateRootHash, final Hash worldStateRootHash,
final BonsaiWorldState forWorldState) { final DiffBasedWorldState forWorldState) {
final Optional<CachedBonsaiWorldView> cachedBonsaiWorldView = final Optional<DiffBasedCachedWorldView> cachedDiffBasedWorldView =
Optional.ofNullable(this.cachedWorldStatesByHash.get(blockHeader.getBlockHash())); Optional.ofNullable(this.cachedWorldStatesByHash.get(blockHeader.getBlockHash()));
if (cachedBonsaiWorldView.isPresent()) { if (cachedDiffBasedWorldView.isPresent()) {
// only replace if it is a layered storage // only replace if it is a layered storage
if (forWorldState.isPersisted() if (forWorldState.isPersisted()
&& cachedBonsaiWorldView.get().getWorldStateStorage() && cachedDiffBasedWorldView.get().getWorldStateStorage()
instanceof BonsaiWorldStateLayerStorage) { instanceof DiffBasedLayeredWorldStateKeyValueStorage) {
LOG.atDebug() LOG.atDebug()
.setMessage("updating layered world state for block {}, state root hash {}") .setMessage("updating layered world state for block {}, state root hash {}")
.addArgument(blockHeader::toLogString) .addArgument(blockHeader::toLogString)
.addArgument(worldStateRootHash::toShortHexString) .addArgument(worldStateRootHash::toShortHexString)
.log(); .log();
cachedBonsaiWorldView cachedDiffBasedWorldView
.get() .get()
.updateWorldStateStorage( .updateWorldStateStorage(
new BonsaiSnapshotWorldStateKeyValueStorage(forWorldState.getWorldStateStorage())); createSnapshotKeyValueStorage(forWorldState.getWorldStateStorage()));
} }
} else { } else {
LOG.atDebug() LOG.atDebug()
@ -93,16 +93,16 @@ public class CachedWorldStorageManager
if (forWorldState.isPersisted()) { if (forWorldState.isPersisted()) {
cachedWorldStatesByHash.put( cachedWorldStatesByHash.put(
blockHeader.getHash(), blockHeader.getHash(),
new CachedBonsaiWorldView( new DiffBasedCachedWorldView(
blockHeader, blockHeader, createSnapshotKeyValueStorage(forWorldState.getWorldStateStorage())));
new BonsaiSnapshotWorldStateKeyValueStorage(forWorldState.getWorldStateStorage())));
} else { } else {
// otherwise, add the layer to the cache // otherwise, add the layer to the cache
cachedWorldStatesByHash.put( cachedWorldStatesByHash.put(
blockHeader.getHash(), blockHeader.getHash(),
new CachedBonsaiWorldView( new DiffBasedCachedWorldView(
blockHeader, blockHeader,
((BonsaiWorldStateLayerStorage) forWorldState.getWorldStateStorage()).clone())); ((DiffBasedLayeredWorldStateKeyValueStorage) forWorldState.getWorldStateStorage())
.clone()));
} }
} }
scrubCachedLayers(blockHeader.getNumber()); scrubCachedLayers(blockHeader.getNumber());
@ -122,15 +122,15 @@ public class CachedWorldStorageManager
} }
} }
public Optional<BonsaiWorldState> getWorldState(final Hash blockHash) { public Optional<DiffBasedWorldState> getWorldState(final Hash blockHash) {
if (cachedWorldStatesByHash.containsKey(blockHash)) { if (cachedWorldStatesByHash.containsKey(blockHash)) {
// return a new worldstate using worldstate storage and an isolated copy of the updater // return a new worldstate using worldstate storage and an isolated copy of the updater
return Optional.ofNullable(cachedWorldStatesByHash.get(blockHash)) return Optional.ofNullable(cachedWorldStatesByHash.get(blockHash))
.map( .map(
cached -> cached ->
new BonsaiWorldState( createWorldState(
archive, archive,
new BonsaiWorldStateLayerStorage(cached.getWorldStateStorage()), createLayeredKeyValueStorage(cached.getWorldStateStorage()),
evmConfiguration)); evmConfiguration));
} }
LOG.atDebug() LOG.atDebug()
@ -141,7 +141,7 @@ public class CachedWorldStorageManager
return Optional.empty(); return Optional.empty();
} }
public Optional<BonsaiWorldState> getNearestWorldState(final BlockHeader blockHeader) { public Optional<DiffBasedWorldState> getNearestWorldState(final BlockHeader blockHeader) {
LOG.atDebug() LOG.atDebug()
.setMessage("getting nearest worldstate for {}") .setMessage("getting nearest worldstate for {}")
.addArgument(blockHeader.toLogString()) .addArgument(blockHeader.toLogString())
@ -149,7 +149,7 @@ public class CachedWorldStorageManager
return Optional.ofNullable( return Optional.ofNullable(
cachedWorldStatesByHash.get(blockHeader.getParentHash())) // search parent block cachedWorldStatesByHash.get(blockHeader.getParentHash())) // search parent block
.map(CachedBonsaiWorldView::getWorldStateStorage) .map(DiffBasedCachedWorldView::getWorldStateStorage)
.or( .or(
() -> { () -> {
// or else search the nearest state in the cache // or else search the nearest state in the cache
@ -158,22 +158,22 @@ public class CachedWorldStorageManager
.addArgument(blockHeader.toLogString()) .addArgument(blockHeader.toLogString())
.log(); .log();
final List<CachedBonsaiWorldView> cachedBonsaiWorldViews = final List<DiffBasedCachedWorldView> cachedDiffBasedWorldViews =
new ArrayList<>(cachedWorldStatesByHash.values()); new ArrayList<>(cachedWorldStatesByHash.values());
return cachedBonsaiWorldViews.stream() return cachedDiffBasedWorldViews.stream()
.sorted( .sorted(
Comparator.comparingLong( Comparator.comparingLong(
view -> Math.abs(blockHeader.getNumber() - view.getBlockNumber()))) view -> Math.abs(blockHeader.getNumber() - view.getBlockNumber())))
.map(CachedBonsaiWorldView::getWorldStateStorage) .map(DiffBasedCachedWorldView::getWorldStateStorage)
.findFirst(); .findFirst();
}) })
.map( .map(
storage -> storage ->
new BonsaiWorldState( // wrap the state in a layered worldstate createWorldState( // wrap the state in a layered worldstate
archive, new BonsaiWorldStateLayerStorage(storage), evmConfiguration)); archive, createLayeredKeyValueStorage(storage), evmConfiguration));
} }
public Optional<BonsaiWorldState> getHeadWorldState( public Optional<DiffBasedWorldState> getHeadWorldState(
final Function<Hash, Optional<BlockHeader>> hashBlockHeaderFunction) { final Function<Hash, Optional<BlockHeader>> hashBlockHeaderFunction) {
LOG.atDebug().setMessage("getting head worldstate").log(); LOG.atDebug().setMessage("getting head worldstate").log();
@ -187,7 +187,7 @@ public class CachedWorldStorageManager
addCachedLayer( addCachedLayer(
blockHeader, blockHeader,
blockHeader.getStateRoot(), blockHeader.getStateRoot(),
new BonsaiWorldState(archive, rootWorldStateStorage, evmConfiguration)); createWorldState(archive, rootWorldStateStorage, evmConfiguration));
return getWorldState(blockHeader.getHash()); return getWorldState(blockHeader.getHash());
}); });
} }
@ -219,4 +219,15 @@ public class CachedWorldStorageManager
public void onCloseStorage() { public void onCloseStorage() {
this.cachedWorldStatesByHash.clear(); this.cachedWorldStatesByHash.clear();
} }
public abstract DiffBasedWorldState createWorldState(
final DiffBasedWorldStateProvider archive,
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final EvmConfiguration evmConfiguration);
public abstract DiffBasedWorldStateKeyValueStorage createLayeredKeyValueStorage(
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage);
public abstract DiffBasedWorldStateKeyValueStorage createSnapshotKeyValueStorage(
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage);
} }

@ -13,30 +13,30 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.cache; package org.hyperledger.besu.ethereum.trie.diffbased.common.cache;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CachedBonsaiWorldView public class DiffBasedCachedWorldView implements StorageSubscriber {
implements BonsaiWorldStateKeyValueStorage.BonsaiStorageSubscriber { private DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage;
private BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage;
private final BlockHeader blockHeader; private final BlockHeader blockHeader;
private long worldViewSubscriberId; private long worldViewSubscriberId;
private static final Logger LOG = LoggerFactory.getLogger(CachedBonsaiWorldView.class); private static final Logger LOG = LoggerFactory.getLogger(DiffBasedCachedWorldView.class);
public CachedBonsaiWorldView( public DiffBasedCachedWorldView(
final BlockHeader blockHeader, final BonsaiWorldStateKeyValueStorage worldView) { final BlockHeader blockHeader, final DiffBasedWorldStateKeyValueStorage worldView) {
this.blockHeader = blockHeader; this.blockHeader = blockHeader;
this.worldStateKeyValueStorage = worldView; this.worldStateKeyValueStorage = worldView;
this.worldViewSubscriberId = worldStateKeyValueStorage.subscribe(this); this.worldViewSubscriberId = worldStateKeyValueStorage.subscribe(this);
} }
public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { public DiffBasedWorldStateKeyValueStorage getWorldStateStorage() {
return worldStateKeyValueStorage; return worldStateKeyValueStorage;
} }
@ -58,10 +58,10 @@ public class CachedBonsaiWorldView
} }
public synchronized void updateWorldStateStorage( public synchronized void updateWorldStateStorage(
final BonsaiWorldStateKeyValueStorage newWorldStateStorage) { final DiffBasedWorldStateKeyValueStorage newWorldStateStorage) {
long newSubscriberId = newWorldStateStorage.subscribe(this); long newSubscriberId = newWorldStateStorage.subscribe(this);
this.worldStateKeyValueStorage.unSubscribe(this.worldViewSubscriberId); this.worldStateKeyValueStorage.unSubscribe(this.worldViewSubscriberId);
BonsaiWorldStateKeyValueStorage oldWorldStateStorage = this.worldStateKeyValueStorage; final DiffBasedWorldStateKeyValueStorage oldWorldStateStorage = this.worldStateKeyValueStorage;
this.worldStateKeyValueStorage = newWorldStateStorage; this.worldStateKeyValueStorage = newWorldStateStorage;
this.worldViewSubscriberId = newSubscriberId; this.worldViewSubscriberId = newSubscriberId;
try { try {

@ -0,0 +1,22 @@
/*
* 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.trie.diffbased.common.storage;
public interface DiffBasedLayeredWorldStateKeyValueStorage
extends DiffBasedSnapshotWorldStateKeyValueStorage {
DiffBasedWorldStateKeyValueStorage clone();
}

@ -0,0 +1,21 @@
/*
* 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.trie.diffbased.common.storage;
public interface DiffBasedSnapshotWorldStateKeyValueStorage {
DiffBasedWorldStateKeyValueStorage getParentWorldStateStorage();
}

@ -0,0 +1,234 @@
/*
* 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.trie.diffbased.common.storage;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat.FlatDbStrategy;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
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;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
import org.hyperledger.besu.util.Subscribers;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class DiffBasedWorldStateKeyValueStorage
implements WorldStateKeyValueStorage, AutoCloseable {
private static final Logger LOG =
LoggerFactory.getLogger(DiffBasedWorldStateKeyValueStorage.class);
// 0x776f726c64526f6f74
public static final byte[] WORLD_ROOT_HASH_KEY = "worldRoot".getBytes(StandardCharsets.UTF_8);
// 0x776f726c64426c6f636b48617368
public static final byte[] WORLD_BLOCK_HASH_KEY =
"worldBlockHash".getBytes(StandardCharsets.UTF_8);
private final AtomicBoolean shouldClose = new AtomicBoolean(false);
protected final AtomicBoolean isClosed = new AtomicBoolean(false);
protected final Subscribers<StorageSubscriber> subscribers = Subscribers.create();
protected final SegmentedKeyValueStorage composedWorldStateStorage;
protected final KeyValueStorage trieLogStorage;
public DiffBasedWorldStateKeyValueStorage(final StorageProvider provider) {
this.composedWorldStateStorage =
provider.getStorageBySegmentIdentifiers(
List.of(
ACCOUNT_INFO_STATE, CODE_STORAGE, ACCOUNT_STORAGE_STORAGE, TRIE_BRANCH_STORAGE));
this.trieLogStorage =
provider.getStorageBySegmentIdentifier(KeyValueSegmentIdentifier.TRIE_LOG_STORAGE);
}
public DiffBasedWorldStateKeyValueStorage(
final SegmentedKeyValueStorage composedWorldStateStorage,
final KeyValueStorage trieLogStorage) {
this.composedWorldStateStorage = composedWorldStateStorage;
this.trieLogStorage = trieLogStorage;
}
public abstract FlatDbMode getFlatDbMode();
public abstract FlatDbStrategy getFlatDbStrategy();
@Override
public abstract DataStorageFormat getDataStorageFormat();
public SegmentedKeyValueStorage getComposedWorldStateStorage() {
return composedWorldStateStorage;
}
public KeyValueStorage getTrieLogStorage() {
return trieLogStorage;
}
public Optional<byte[]> getTrieLog(final Hash blockHash) {
return trieLogStorage.get(blockHash.toArrayUnsafe());
}
public Stream<byte[]> streamTrieLogKeys(final long limit) {
return trieLogStorage.streamKeys().limit(limit);
}
public Optional<Bytes> getStateTrieNode(final Bytes location) {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, location.toArrayUnsafe())
.map(Bytes::wrap);
}
public Optional<Bytes> getWorldStateRootHash() {
return composedWorldStateStorage.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY).map(Bytes::wrap);
}
public Optional<Hash> getWorldStateBlockHash() {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY)
.map(Bytes32::wrap)
.map(Hash::wrap);
}
public Map<Bytes32, Bytes> streamFlatAccounts(
final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbStrategy()
.streamAccountFlatDatabase(composedWorldStateStorage, startKeyHash, endKeyHash, max);
}
public Map<Bytes32, Bytes> streamFlatStorages(
final Hash accountHash, final Bytes startKeyHash, final Bytes32 endKeyHash, final long max) {
return getFlatDbStrategy()
.streamStorageFlatDatabase(
composedWorldStateStorage, accountHash, startKeyHash, endKeyHash, max);
}
public boolean isWorldStateAvailable(final Bytes32 rootHash, final Hash blockHash) {
return composedWorldStateStorage
.get(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY)
.map(Bytes32::wrap)
.map(hash -> hash.equals(rootHash) || trieLogStorage.containsKey(blockHash.toArrayUnsafe()))
.orElse(false);
}
@Override
public void clear() {
subscribers.forEach(StorageSubscriber::onClearStorage);
getFlatDbStrategy().clearAll(composedWorldStateStorage);
composedWorldStateStorage.clear(TRIE_BRANCH_STORAGE);
trieLogStorage.clear();
}
public void clearTrieLog() {
subscribers.forEach(StorageSubscriber::onClearTrieLog);
trieLogStorage.clear();
}
public void clearFlatDatabase() {
subscribers.forEach(StorageSubscriber::onClearFlatDatabaseStorage);
getFlatDbStrategy().resetOnResync(composedWorldStateStorage);
}
@Override
public abstract Updater updater();
public boolean pruneTrieLog(final Hash blockHash) {
try {
return trieLogStorage.tryDelete(blockHash.toArrayUnsafe());
} catch (Exception e) {
LOG.error("Error pruning trie log for block hash {}", blockHash, e);
return false;
}
}
@Override
public synchronized void close() throws Exception {
// when the storage clears, close
shouldClose.set(true);
tryClose();
}
public synchronized long subscribe(final StorageSubscriber sub) {
if (isClosed.get()) {
throw new RuntimeException("Storage is marked to close or has already closed");
}
return subscribers.subscribe(sub);
}
public synchronized void unSubscribe(final long id) {
subscribers.unsubscribe(id);
try {
tryClose();
} catch (Exception e) {
LOG.atWarn()
.setMessage("exception while trying to close : {}")
.addArgument(e::getMessage)
.log();
}
}
protected synchronized void tryClose() throws Exception {
if (shouldClose.get() && subscribers.getSubscriberCount() < 1) {
doClose();
}
}
protected synchronized void doClose() throws Exception {
if (!isClosed.get()) {
// alert any subscribers we are closing:
subscribers.forEach(StorageSubscriber::onCloseStorage);
// close all of the KeyValueStorages:
composedWorldStateStorage.close();
trieLogStorage.close();
// set storage closed
isClosed.set(true);
}
}
public interface Updater extends WorldStateKeyValueStorage.Updater {
DiffBasedWorldStateKeyValueStorage.Updater saveWorldState(
final Bytes blockHash, final Bytes32 nodeHash, final Bytes node);
SegmentedKeyValueStorageTransaction getWorldStateTransaction();
KeyValueStorageTransaction getTrieLogStorageTransaction();
@Override
void commit();
void rollback();
}
}

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage; import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorage;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_STORAGE_STORAGE;

@ -13,11 +13,13 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.CODE_STORAGE;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat.FullFlatDbStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat.PartialFlatDbStrategy;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;

@ -12,12 +12,12 @@
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import java.util.Optional; import java.util.Optional;
@ -30,10 +30,10 @@ public class NoOpTrieLogManager extends TrieLogManager {
@Override @Override
public synchronized void saveTrieLog( public synchronized void saveTrieLog(
final BonsaiWorldStateUpdateAccumulator localUpdater, final DiffBasedWorldStateUpdateAccumulator<?> localUpdater,
final Hash forWorldStateRootHash, final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader, final BlockHeader forBlockHeader,
final BonsaiWorldState forWorldState) { final DiffBasedWorldState forWorldState) {
// notify trie log added observers, synchronously // notify trie log added observers, synchronously
TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader); TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader);
trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog))); trieLogObservers.forEach(o -> o.onTrieLogAdded(new TrieLogAddedEvent(trieLog)));

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent; import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent;

@ -14,7 +14,7 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@ -22,7 +22,7 @@ import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
import java.util.HashMap; import java.util.HashMap;
@ -49,21 +49,21 @@ public class TrieLogLayer implements TrieLog {
protected Hash blockHash; protected Hash blockHash;
protected Optional<Long> blockNumber = Optional.empty(); protected Optional<Long> blockNumber = Optional.empty();
Map<Address, BonsaiValue<AccountValue>> getAccounts() { Map<Address, DiffBasedValue<AccountValue>> getAccounts() {
return accounts; return accounts;
} }
Map<Address, BonsaiValue<Bytes>> getCode() { Map<Address, DiffBasedValue<Bytes>> getCode() {
return code; return code;
} }
Map<Address, Map<StorageSlotKey, BonsaiValue<UInt256>>> getStorage() { Map<Address, Map<StorageSlotKey, DiffBasedValue<UInt256>>> getStorage() {
return storage; return storage;
} }
protected final Map<Address, BonsaiValue<AccountValue>> accounts; protected final Map<Address, DiffBasedValue<AccountValue>> accounts;
protected final Map<Address, BonsaiValue<Bytes>> code; protected final Map<Address, DiffBasedValue<Bytes>> code;
protected final Map<Address, Map<StorageSlotKey, BonsaiValue<UInt256>>> storage; protected final Map<Address, Map<StorageSlotKey, DiffBasedValue<UInt256>>> storage;
protected boolean frozen = false; protected boolean frozen = false;
public TrieLogLayer() { public TrieLogLayer() {
@ -104,14 +104,14 @@ public class TrieLogLayer implements TrieLog {
public TrieLogLayer addAccountChange( public TrieLogLayer addAccountChange(
final Address address, final AccountValue oldValue, final AccountValue newValue) { final Address address, final AccountValue oldValue, final AccountValue newValue) {
checkState(!frozen, "Layer is Frozen"); checkState(!frozen, "Layer is Frozen");
accounts.put(address, new BonsaiValue<>(oldValue, newValue)); accounts.put(address, new DiffBasedValue<>(oldValue, newValue));
return this; return this;
} }
public TrieLogLayer addCodeChange( public TrieLogLayer addCodeChange(
final Address address, final Bytes oldValue, final Bytes newValue, final Hash blockHash) { final Address address, final Bytes oldValue, final Bytes newValue, final Hash blockHash) {
checkState(!frozen, "Layer is Frozen"); checkState(!frozen, "Layer is Frozen");
code.put(address, new BonsaiValue<>(oldValue, newValue, newValue == null)); code.put(address, new DiffBasedValue<>(oldValue, newValue, newValue == null));
return this; return this;
} }
@ -123,22 +123,22 @@ public class TrieLogLayer implements TrieLog {
checkState(!frozen, "Layer is Frozen"); checkState(!frozen, "Layer is Frozen");
storage storage
.computeIfAbsent(address, a -> new TreeMap<>()) .computeIfAbsent(address, a -> new TreeMap<>())
.put(slot, new BonsaiValue<>(oldValue, newValue)); .put(slot, new DiffBasedValue<>(oldValue, newValue));
return this; return this;
} }
@Override @Override
public Map<Address, BonsaiValue<AccountValue>> getAccountChanges() { public Map<Address, DiffBasedValue<AccountValue>> getAccountChanges() {
return accounts; return accounts;
} }
@Override @Override
public Map<Address, BonsaiValue<Bytes>> getCodeChanges() { public Map<Address, DiffBasedValue<Bytes>> getCodeChanges() {
return code; return code;
} }
@Override @Override
public Map<Address, Map<StorageSlotKey, BonsaiValue<UInt256>>> getStorageChanges() { public Map<Address, Map<StorageSlotKey, DiffBasedValue<UInt256>>> getStorageChanges() {
return storage; return storage;
} }
@ -147,18 +147,18 @@ public class TrieLogLayer implements TrieLog {
} }
@Override @Override
public Map<StorageSlotKey, BonsaiValue<UInt256>> getStorageChanges(final Address address) { public Map<StorageSlotKey, DiffBasedValue<UInt256>> getStorageChanges(final Address address) {
return storage.getOrDefault(address, Map.of()); return storage.getOrDefault(address, Map.of());
} }
@Override @Override
public Optional<Bytes> getPriorCode(final Address address) { public Optional<Bytes> getPriorCode(final Address address) {
return Optional.ofNullable(code.get(address)).map(BonsaiValue::getPrior); return Optional.ofNullable(code.get(address)).map(DiffBasedValue::getPrior);
} }
@Override @Override
public Optional<Bytes> getCode(final Address address) { public Optional<Bytes> getCode(final Address address) {
return Optional.ofNullable(code.get(address)).map(BonsaiValue::getUpdated); return Optional.ofNullable(code.get(address)).map(DiffBasedValue::getUpdated);
} }
@Override @Override
@ -166,7 +166,7 @@ public class TrieLogLayer implements TrieLog {
final Address address, final StorageSlotKey storageSlotKey) { final Address address, final StorageSlotKey storageSlotKey) {
return Optional.ofNullable(storage.get(address)) return Optional.ofNullable(storage.get(address))
.map(i -> i.get(storageSlotKey)) .map(i -> i.get(storageSlotKey))
.map(BonsaiValue::getPrior); .map(DiffBasedValue::getPrior);
} }
@Override @Override
@ -174,24 +174,24 @@ public class TrieLogLayer implements TrieLog {
final Address address, final StorageSlotKey storageSlotKey) { final Address address, final StorageSlotKey storageSlotKey) {
return Optional.ofNullable(storage.get(address)) return Optional.ofNullable(storage.get(address))
.map(i -> i.get(storageSlotKey)) .map(i -> i.get(storageSlotKey))
.map(BonsaiValue::getUpdated); .map(DiffBasedValue::getUpdated);
} }
@Override @Override
public Optional<AccountValue> getPriorAccount(final Address address) { public Optional<AccountValue> getPriorAccount(final Address address) {
return Optional.ofNullable(accounts.get(address)).map(BonsaiValue::getPrior); return Optional.ofNullable(accounts.get(address)).map(DiffBasedValue::getPrior);
} }
@Override @Override
public Optional<AccountValue> getAccount(final Address address) { public Optional<AccountValue> getAccount(final Address address) {
return Optional.ofNullable(accounts.get(address)).map(BonsaiValue::getUpdated); return Optional.ofNullable(accounts.get(address)).map(DiffBasedValue::getUpdated);
} }
public String dump() { public String dump() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("TrieLog{" + "blockHash=").append(blockHash).append(frozen).append('}'); sb.append("TrieLog{" + "blockHash=").append(blockHash).append(frozen).append('}');
sb.append("accounts\n"); sb.append("accounts\n");
for (final Map.Entry<Address, BonsaiValue<AccountValue>> account : accounts.entrySet()) { for (final Map.Entry<Address, DiffBasedValue<AccountValue>> account : accounts.entrySet()) {
sb.append(" : ").append(account.getKey()).append("\n"); sb.append(" : ").append(account.getKey()).append("\n");
if (Objects.equals(account.getValue().getPrior(), account.getValue().getUpdated())) { if (Objects.equals(account.getValue().getPrior(), account.getValue().getUpdated())) {
sb.append(" = ").append(account.getValue().getUpdated()).append("\n"); sb.append(" = ").append(account.getValue().getUpdated()).append("\n");
@ -201,7 +201,7 @@ public class TrieLogLayer implements TrieLog {
} }
} }
sb.append("code").append("\n"); sb.append("code").append("\n");
for (final Map.Entry<Address, BonsaiValue<Bytes>> code : code.entrySet()) { for (final Map.Entry<Address, DiffBasedValue<Bytes>> code : code.entrySet()) {
sb.append(" : ").append(code.getKey()).append("\n"); sb.append(" : ").append(code.getKey()).append("\n");
if (Objects.equals(code.getValue().getPrior(), code.getValue().getUpdated())) { if (Objects.equals(code.getValue().getPrior(), code.getValue().getUpdated())) {
sb.append(" = ").append(code.getValue().getPrior()).append("\n"); sb.append(" = ").append(code.getValue().getPrior()).append("\n");
@ -211,10 +211,10 @@ public class TrieLogLayer implements TrieLog {
} }
} }
sb.append("Storage").append("\n"); sb.append("Storage").append("\n");
for (final Map.Entry<Address, Map<StorageSlotKey, BonsaiValue<UInt256>>> storage : for (final Map.Entry<Address, Map<StorageSlotKey, DiffBasedValue<UInt256>>> storage :
storage.entrySet()) { storage.entrySet()) {
sb.append(" : ").append(storage.getKey()).append("\n"); sb.append(" : ").append(storage.getKey()).append("\n");
for (final Map.Entry<StorageSlotKey, BonsaiValue<UInt256>> slot : for (final Map.Entry<StorageSlotKey, DiffBasedValue<UInt256>> slot :
storage.getValue().entrySet()) { storage.getValue().entrySet()) {
final UInt256 originalValue = slot.getValue().getPrior(); final UInt256 originalValue = slot.getValue().getPrior();
final UInt256 updatedValue = slot.getValue().getUpdated(); final UInt256 updatedValue = slot.getValue().getUpdated();

@ -13,14 +13,15 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.plugin.BesuContext; import org.hyperledger.besu.plugin.BesuContext;
import org.hyperledger.besu.plugin.services.TrieLogService; import org.hyperledger.besu.plugin.services.TrieLogService;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;
@ -41,7 +42,7 @@ public class TrieLogManager {
private static final Logger LOG = LoggerFactory.getLogger(TrieLogManager.class); private static final Logger LOG = LoggerFactory.getLogger(TrieLogManager.class);
public static final long LOG_RANGE_LIMIT = 1000; // restrict trielog range queries to 1k logs public static final long LOG_RANGE_LIMIT = 1000; // restrict trielog range queries to 1k logs
protected final Blockchain blockchain; protected final Blockchain blockchain;
protected final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; protected final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage;
protected final long maxLayersToLoad; protected final long maxLayersToLoad;
protected final Subscribers<TrieLogEvent.TrieLogObserver> trieLogObservers = Subscribers.create(); protected final Subscribers<TrieLogEvent.TrieLogObserver> trieLogObservers = Subscribers.create();
@ -50,7 +51,7 @@ public class TrieLogManager {
public TrieLogManager( public TrieLogManager(
final Blockchain blockchain, final Blockchain blockchain,
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final long maxLayersToLoad, final long maxLayersToLoad,
final BesuContext pluginContext) { final BesuContext pluginContext) {
this.blockchain = blockchain; this.blockchain = blockchain;
@ -60,15 +61,15 @@ public class TrieLogManager {
} }
public synchronized void saveTrieLog( public synchronized void saveTrieLog(
final BonsaiWorldStateUpdateAccumulator localUpdater, final DiffBasedWorldStateUpdateAccumulator<?> localUpdater,
final Hash forWorldStateRootHash, final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader, final BlockHeader forBlockHeader,
final BonsaiWorldState forWorldState) { final DiffBasedWorldState forWorldState) {
// do not overwrite a trielog layer that already exists in the database. // do not overwrite a trielog layer that already exists in the database.
// if it's only in memory we need to save it // if it's only in memory we need to save it
// for example, in case of reorg we don't replace a trielog layer // for example, in case of reorg we don't replace a trielog layer
if (rootWorldStateStorage.getTrieLog(forBlockHeader.getHash()).isEmpty()) { if (rootWorldStateStorage.getTrieLog(forBlockHeader.getHash()).isEmpty()) {
final BonsaiWorldStateKeyValueStorage.Updater stateUpdater = final DiffBasedWorldStateKeyValueStorage.Updater stateUpdater =
forWorldState.getWorldStateStorage().updater(); forWorldState.getWorldStateStorage().updater();
boolean success = false; boolean success = false;
try { try {
@ -90,7 +91,7 @@ public class TrieLogManager {
} }
private TrieLog prepareTrieLog( private TrieLog prepareTrieLog(
final BlockHeader blockHeader, final BonsaiWorldStateUpdateAccumulator localUpdater) { final BlockHeader blockHeader, final DiffBasedWorldStateUpdateAccumulator<?> localUpdater) {
LOG.atDebug() LOG.atDebug()
.setMessage("Adding layered world state for {}") .setMessage("Adding layered world state for {}")
.addArgument(blockHeader::toLogString) .addArgument(blockHeader::toLogString)
@ -104,7 +105,7 @@ public class TrieLogManager {
final BlockHeader blockHeader, final BlockHeader blockHeader,
final Hash worldStateRootHash, final Hash worldStateRootHash,
final TrieLog trieLog, final TrieLog trieLog,
final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) { final DiffBasedWorldStateKeyValueStorage.Updater stateUpdater) {
LOG.atDebug() LOG.atDebug()
.setMessage("Persisting trie log for block hash {} and world state root {}") .setMessage("Persisting trie log for block hash {} and world state root {}")
.addArgument(blockHeader::toLogString) .addArgument(blockHeader::toLogString)

@ -13,13 +13,13 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent; import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent;
import java.util.Comparator; import java.util.Comparator;
@ -41,7 +41,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver {
private final int pruningLimit; private final int pruningLimit;
private final int loadingLimit; private final int loadingLimit;
private final BonsaiWorldStateKeyValueStorage rootWorldStateStorage; private final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage;
private final Blockchain blockchain; private final Blockchain blockchain;
private final Consumer<Runnable> executeAsync; private final Consumer<Runnable> executeAsync;
private final long numBlocksToRetain; private final long numBlocksToRetain;
@ -51,7 +51,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver {
TreeMultimap.create(Comparator.reverseOrder(), Comparator.naturalOrder()); TreeMultimap.create(Comparator.reverseOrder(), Comparator.naturalOrder());
public TrieLogPruner( public TrieLogPruner(
final BonsaiWorldStateKeyValueStorage rootWorldStateStorage, final DiffBasedWorldStateKeyValueStorage rootWorldStateStorage,
final Blockchain blockchain, final Blockchain blockchain,
final Consumer<Runnable> executeAsync, final Consumer<Runnable> executeAsync,
final long numBlocksToRetain, final long numBlocksToRetain,
@ -100,7 +100,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver {
} }
} }
void addToPruneQueue(final long blockNumber, final Hash blockHash) { public void addToPruneQueue(final long blockNumber, final Hash blockHash) {
LOG.atTrace() LOG.atTrace()
.setMessage("adding trie log to queue for later pruning blockNumber {}; blockHash {}") .setMessage("adding trie log to queue for later pruning blockNumber {}; blockHash {}")
.addArgument(blockNumber) .addArgument(blockNumber)
@ -109,7 +109,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver {
trieLogBlocksAndForksByDescendingBlockNumber.put(blockNumber, blockHash); trieLogBlocksAndForksByDescendingBlockNumber.put(blockNumber, blockHash);
} }
int pruneFromQueue() { public int pruneFromQueue() {
final long retainAboveThisBlock = blockchain.getChainHeadBlockNumber() - numBlocksToRetain; final long retainAboveThisBlock = blockchain.getChainHeadBlockNumber() - numBlocksToRetain;
final Optional<Hash> finalized = blockchain.getFinalized(); final Optional<Hash> finalized = blockchain.getFinalized();
if (requireFinalizedBlock && finalized.isEmpty()) { if (requireFinalizedBlock && finalized.isEmpty()) {

@ -0,0 +1,334 @@
/*
* 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.trie.diffbased.common.worldview;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import static org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY;
import static org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.StorageSubscriber;
import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedLayeredWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedSnapshotWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.plugin.services.storage.SegmentIdentifier;
import org.hyperledger.besu.plugin.services.storage.SegmentedKeyValueStorageTransaction;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class DiffBasedWorldState
implements MutableWorldState, DiffBasedWorldView, StorageSubscriber {
private static final Logger LOG = LoggerFactory.getLogger(DiffBasedWorldState.class);
protected DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage;
protected final DiffBasedCachedWorldStorageManager cachedWorldStorageManager;
protected final TrieLogManager trieLogManager;
protected DiffBasedWorldStateUpdateAccumulator<?> accumulator;
protected Hash worldStateRootHash;
protected Hash worldStateBlockHash;
protected boolean isFrozen;
protected DiffBasedWorldState(
final DiffBasedWorldStateKeyValueStorage worldStateKeyValueStorage,
final DiffBasedCachedWorldStorageManager cachedWorldStorageManager,
final TrieLogManager trieLogManager) {
this.worldStateKeyValueStorage = worldStateKeyValueStorage;
this.worldStateRootHash =
Hash.wrap(
Bytes32.wrap(
worldStateKeyValueStorage.getWorldStateRootHash().orElse(getEmptyTrieHash())));
this.worldStateBlockHash =
Hash.wrap(
Bytes32.wrap(worldStateKeyValueStorage.getWorldStateBlockHash().orElse(Hash.ZERO)));
this.cachedWorldStorageManager = cachedWorldStorageManager;
this.trieLogManager = trieLogManager;
}
/**
* Having a protected method to override the accumulator solves the chicken-egg problem of needing
* a worldstate reference (this) when construction the Accumulator.
*
* @param accumulator accumulator to use.
*/
public void setAccumulator(final DiffBasedWorldStateUpdateAccumulator<?> accumulator) {
this.accumulator = accumulator;
}
/**
* Returns the world state block hash of this world state
*
* @return the world state block hash.
*/
public Hash getWorldStateBlockHash() {
return worldStateBlockHash;
}
/**
* Returns the world state root hash of this world state
*
* @return the world state root hash.
*/
public Hash getWorldStateRootHash() {
return worldStateRootHash;
}
@Override
public boolean isPersisted() {
return isPersisted(worldStateKeyValueStorage);
}
private boolean isPersisted(final WorldStateKeyValueStorage worldStateKeyValueStorage) {
return !(worldStateKeyValueStorage instanceof DiffBasedSnapshotWorldStateKeyValueStorage);
}
/**
* Reset the worldState to this block header
*
* @param blockHeader block to use
*/
public void resetWorldStateTo(final BlockHeader blockHeader) {
worldStateBlockHash = blockHeader.getBlockHash();
worldStateRootHash = blockHeader.getStateRoot();
}
@Override
public DiffBasedWorldStateKeyValueStorage getWorldStateStorage() {
return worldStateKeyValueStorage;
}
public DiffBasedWorldStateUpdateAccumulator<?> getAccumulator() {
return accumulator;
}
@Override
public void persist(final BlockHeader blockHeader) {
final Optional<BlockHeader> maybeBlockHeader = Optional.ofNullable(blockHeader);
LOG.atDebug()
.setMessage("Persist world state for block {}")
.addArgument(maybeBlockHeader)
.log();
final DiffBasedWorldStateUpdateAccumulator<?> localCopy = accumulator.copy();
boolean success = false;
final DiffBasedWorldStateKeyValueStorage.Updater stateUpdater =
worldStateKeyValueStorage.updater();
Runnable saveTrieLog = () -> {};
try {
final Hash newWorldStateRootHash =
calculateRootHash(isFrozen ? Optional.empty() : Optional.of(stateUpdater), accumulator);
// if we are persisted with a block header, and the prior state is the parent
// then persist the TrieLog for that transition.
// If specified but not a direct descendant simply store the new block hash.
if (blockHeader != null) {
verifyWorldStateRoot(newWorldStateRootHash, blockHeader);
saveTrieLog =
() -> {
trieLogManager.saveTrieLog(localCopy, newWorldStateRootHash, blockHeader, this);
// not save a frozen state in the cache
if (!isFrozen) {
cachedWorldStorageManager.addCachedLayer(blockHeader, newWorldStateRootHash, this);
}
};
stateUpdater
.getWorldStateTransaction()
.put(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe());
worldStateBlockHash = blockHeader.getHash();
} else {
stateUpdater.getWorldStateTransaction().remove(TRIE_BRANCH_STORAGE, WORLD_BLOCK_HASH_KEY);
worldStateBlockHash = null;
}
stateUpdater
.getWorldStateTransaction()
.put(TRIE_BRANCH_STORAGE, WORLD_ROOT_HASH_KEY, newWorldStateRootHash.toArrayUnsafe());
worldStateRootHash = newWorldStateRootHash;
success = true;
} finally {
if (success) {
stateUpdater.commit();
accumulator.reset();
saveTrieLog.run();
} else {
stateUpdater.rollback();
accumulator.reset();
}
}
}
protected void verifyWorldStateRoot(final Hash calculatedStateRoot, final BlockHeader header) {
if (!calculatedStateRoot.equals(header.getStateRoot())) {
throw new RuntimeException(
"World State Root does not match expected value, header "
+ header.getStateRoot().toHexString()
+ " calculated "
+ calculatedStateRoot.toHexString());
}
}
@Override
public WorldUpdater updater() {
return accumulator;
}
@Override
public Hash rootHash() {
if (isFrozen && accumulator.isAccumulatorStateChanged()) {
worldStateRootHash = calculateRootHash(Optional.empty(), accumulator.copy());
accumulator.resetAccumulatorStateChanged();
}
return Hash.wrap(worldStateRootHash);
}
protected static final KeyValueStorageTransaction noOpTx =
new KeyValueStorageTransaction() {
@Override
public void put(final byte[] key, final byte[] value) {
// no-op
}
@Override
public void remove(final byte[] key) {
// no-op
}
@Override
public void commit() throws StorageException {
// no-op
}
@Override
public void rollback() {
// no-op
}
};
protected static final SegmentedKeyValueStorageTransaction noOpSegmentedTx =
new SegmentedKeyValueStorageTransaction() {
@Override
public void put(
final SegmentIdentifier segmentIdentifier, final byte[] key, final byte[] value) {
// no-op
}
@Override
public void remove(final SegmentIdentifier segmentIdentifier, final byte[] key) {
// no-op
}
@Override
public void commit() throws StorageException {
// no-op
}
@Override
public void rollback() {
// no-op
}
};
public Hash blockHash() {
return worldStateBlockHash;
}
@Override
public Stream<StreamableAccount> streamAccounts(final Bytes32 startKeyHash, final int limit) {
throw new RuntimeException("storage format do not provide account streaming.");
}
@Override
public UInt256 getPriorStorageValue(final Address address, final UInt256 storageKey) {
return getStorageValue(address, storageKey);
}
@Override
public void close() {
try {
if (!isPersisted()) {
this.worldStateKeyValueStorage.close();
if (isFrozen) {
closeFrozenStorage();
}
}
} catch (Exception e) {
// no op
}
}
private void closeFrozenStorage() {
try {
final DiffBasedLayeredWorldStateKeyValueStorage worldStateLayerStorage =
(DiffBasedLayeredWorldStateKeyValueStorage) worldStateKeyValueStorage;
if (!isPersisted(worldStateLayerStorage.getParentWorldStateStorage())) {
worldStateLayerStorage.getParentWorldStateStorage().close();
}
} catch (Exception e) {
// no op
}
}
@Override
public abstract Hash frontierRootHash();
@Override
public abstract MutableWorldState freeze();
@Override
public abstract Account get(final Address address);
@Override
public abstract UInt256 getStorageValue(final Address address, final UInt256 storageKey);
@Override
public abstract Optional<UInt256> getStorageValueByStorageSlotKey(
final Address address, final StorageSlotKey storageSlotKey);
@Override
public abstract Optional<Bytes> getCode(@Nonnull final Address address, final Hash codeHash);
protected abstract Hash calculateRootHash(
final Optional<DiffBasedWorldStateKeyValueStorage.Updater> maybeStateUpdater,
final DiffBasedWorldStateUpdateAccumulator<?> worldStateUpdater);
protected abstract Hash getEmptyTrieHash();
}

@ -1,5 +1,5 @@
/* /*
* Copyright ConsenSys AG. * Copyright Hyperledger Besu Contributors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * 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 * the License. You may obtain a copy of the License at
@ -11,16 +11,15 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.worldview; package org.hyperledger.besu.ethereum.trie.diffbased.common.worldview;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.evm.worldstate.WorldView; import org.hyperledger.besu.evm.worldstate.WorldView;
@ -31,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public interface BonsaiWorldView extends WorldView { public interface DiffBasedWorldView extends WorldView {
Optional<Bytes> getCode(Address address, final Hash codeHash); Optional<Bytes> getCode(Address address, final Hash codeHash);
@ -59,7 +58,7 @@ public interface BonsaiWorldView extends WorldView {
boolean isPersisted(); boolean isPersisted();
BonsaiWorldStateKeyValueStorage getWorldStateStorage(); DiffBasedWorldStateKeyValueStorage getWorldStateStorage();
WorldUpdater updater(); WorldUpdater updater();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright ConsenSys AG. * Copyright Hyperledger Besu Contributors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * 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 * the License. You may obtain a copy of the License at
@ -11,10 +11,9 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.worldview; package org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator;
import org.hyperledger.besu.datatypes.AccountValue; import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
@ -23,9 +22,14 @@ import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedAccount;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.AccountConsumingMap;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.Consumer;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.StorageConsumingMap;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -44,42 +48,40 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function; import java.util.function.Function;
import javax.annotation.Nonnull;
import com.google.common.collect.ForwardingMap;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class BonsaiWorldStateUpdateAccumulator @SuppressWarnings("unchecked")
extends AbstractWorldUpdater<BonsaiWorldView, BonsaiAccount> public abstract class DiffBasedWorldStateUpdateAccumulator<ACCOUNT extends DiffBasedAccount>
implements BonsaiWorldView, TrieLogAccumulator { extends AbstractWorldUpdater<DiffBasedWorldView, ACCOUNT>
implements DiffBasedWorldView, TrieLogAccumulator {
private static final Logger LOG = private static final Logger LOG =
LoggerFactory.getLogger(BonsaiWorldStateUpdateAccumulator.class); LoggerFactory.getLogger(DiffBasedWorldStateUpdateAccumulator.class);
protected final Consumer<BonsaiValue<BonsaiAccount>> accountPreloader; protected final Consumer<DiffBasedValue<ACCOUNT>> accountPreloader;
protected final Consumer<StorageSlotKey> storagePreloader; protected final Consumer<StorageSlotKey> storagePreloader;
private final AccountConsumingMap<BonsaiValue<BonsaiAccount>> accountsToUpdate; private final AccountConsumingMap<DiffBasedValue<ACCOUNT>> accountsToUpdate;
private final Map<Address, BonsaiValue<Bytes>> codeToUpdate = new ConcurrentHashMap<>(); private final Map<Address, DiffBasedValue<Bytes>> codeToUpdate = new ConcurrentHashMap<>();
private final Set<Address> storageToClear = Collections.synchronizedSet(new HashSet<>()); private final Set<Address> storageToClear = Collections.synchronizedSet(new HashSet<>());
protected final EvmConfiguration evmConfiguration; protected final EvmConfiguration evmConfiguration;
// storage sub mapped by _hashed_ key. This is because in self_destruct calls we need to // storage sub mapped by _hashed_ key. This is because in self_destruct calls we need to
// enumerate the old storage and delete it. Those are trie stored by hashed key by spec and the // enumerate the old storage and delete it. Those are trie stored by hashed key by spec and the
// alternative was to keep a giant pre-image cache of the entire trie. // alternative was to keep a giant pre-image cache of the entire trie.
private final Map<Address, StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>>> private final Map<Address, StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>>>
storageToUpdate = new ConcurrentHashMap<>(); storageToUpdate = new ConcurrentHashMap<>();
private final Map<UInt256, Hash> storageKeyHashLookup = new ConcurrentHashMap<>(); private final Map<UInt256, Hash> storageKeyHashLookup = new ConcurrentHashMap<>();
protected boolean isAccumulatorStateChanged; protected boolean isAccumulatorStateChanged;
public BonsaiWorldStateUpdateAccumulator( public DiffBasedWorldStateUpdateAccumulator(
final BonsaiWorldView world, final DiffBasedWorldView world,
final Consumer<BonsaiValue<BonsaiAccount>> accountPreloader, final Consumer<DiffBasedValue<ACCOUNT>> accountPreloader,
final Consumer<StorageSlotKey> storagePreloader, final Consumer<StorageSlotKey> storagePreloader,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
super(world, evmConfiguration); super(world, evmConfiguration);
@ -90,15 +92,7 @@ public class BonsaiWorldStateUpdateAccumulator
this.evmConfiguration = evmConfiguration; this.evmConfiguration = evmConfiguration;
} }
public BonsaiWorldStateUpdateAccumulator copy() { protected void cloneFromUpdater(final DiffBasedWorldStateUpdateAccumulator<ACCOUNT> source) {
final BonsaiWorldStateUpdateAccumulator copy =
new BonsaiWorldStateUpdateAccumulator(
wrappedWorldView(), accountPreloader, storagePreloader, evmConfiguration);
copy.cloneFromUpdater(this);
return copy;
}
void cloneFromUpdater(final BonsaiWorldStateUpdateAccumulator source) {
accountsToUpdate.putAll(source.getAccountsToUpdate()); accountsToUpdate.putAll(source.getAccountsToUpdate());
codeToUpdate.putAll(source.codeToUpdate); codeToUpdate.putAll(source.codeToUpdate);
storageToClear.addAll(source.storageToClear); storageToClear.addAll(source.storageToClear);
@ -108,14 +102,25 @@ public class BonsaiWorldStateUpdateAccumulator
this.isAccumulatorStateChanged = true; this.isAccumulatorStateChanged = true;
} }
protected Consumer<DiffBasedValue<ACCOUNT>> getAccountPreloader() {
return accountPreloader;
}
protected Consumer<StorageSlotKey> getStoragePreloader() {
return storagePreloader;
}
protected EvmConfiguration getEvmConfiguration() {
return evmConfiguration;
}
@Override @Override
public Account get(final Address address) { public Account get(final Address address) {
return super.get(address); return super.get(address);
} }
@Override @Override
protected UpdateTrackingAccount<BonsaiAccount> track( protected UpdateTrackingAccount<ACCOUNT> track(final UpdateTrackingAccount<ACCOUNT> account) {
final UpdateTrackingAccount<BonsaiAccount> account) {
return super.track(account); return super.track(account);
} }
@ -126,21 +131,21 @@ public class BonsaiWorldStateUpdateAccumulator
@Override @Override
public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) {
BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address); DiffBasedValue<ACCOUNT> diffBasedValue = accountsToUpdate.get(address);
if (bonsaiValue == null) { if (diffBasedValue == null) {
bonsaiValue = new BonsaiValue<>(null, null); diffBasedValue = new DiffBasedValue<>(null, null);
accountsToUpdate.put(address, bonsaiValue); accountsToUpdate.put(address, diffBasedValue);
} else if (bonsaiValue.getUpdated() != null) { } else if (diffBasedValue.getUpdated() != null) {
if (bonsaiValue.getUpdated().isEmpty()) { if (diffBasedValue.getUpdated().isEmpty()) {
return track(new UpdateTrackingAccount<>(bonsaiValue.getUpdated())); return track(new UpdateTrackingAccount<>(diffBasedValue.getUpdated()));
} else { } else {
throw new IllegalStateException("Cannot create an account when one already exists"); throw new IllegalStateException("Cannot create an account when one already exists");
} }
} }
final BonsaiAccount newAccount = final ACCOUNT newAccount =
new BonsaiAccount( createAccount(
this, this,
address, address,
hashAndSaveAccountPreImage(address), hashAndSaveAccountPreImage(address),
@ -149,17 +154,17 @@ public class BonsaiWorldStateUpdateAccumulator
Hash.EMPTY_TRIE_HASH, Hash.EMPTY_TRIE_HASH,
Hash.EMPTY, Hash.EMPTY,
true); true);
bonsaiValue.setUpdated(newAccount); diffBasedValue.setUpdated(newAccount);
return track(new UpdateTrackingAccount<>(newAccount)); return track(new UpdateTrackingAccount<>(newAccount));
} }
@Override @Override
public Map<Address, BonsaiValue<BonsaiAccount>> getAccountsToUpdate() { public Map<Address, DiffBasedValue<ACCOUNT>> getAccountsToUpdate() {
return accountsToUpdate; return accountsToUpdate;
} }
@Override @Override
public Map<Address, BonsaiValue<Bytes>> getCodeToUpdate() { public Map<Address, DiffBasedValue<Bytes>> getCodeToUpdate() {
return codeToUpdate; return codeToUpdate;
} }
@ -168,40 +173,41 @@ public class BonsaiWorldStateUpdateAccumulator
} }
@Override @Override
public Map<Address, StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>>> public Map<Address, StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>>>
getStorageToUpdate() { getStorageToUpdate() {
return storageToUpdate; return storageToUpdate;
} }
@Override @Override
protected BonsaiAccount getForMutation(final Address address) { protected ACCOUNT getForMutation(final Address address) {
return loadAccount(address, BonsaiValue::getUpdated); return loadAccount(address, DiffBasedValue::getUpdated);
} }
protected BonsaiAccount loadAccount( protected ACCOUNT loadAccount(
final Address address, final Address address, final Function<DiffBasedValue<ACCOUNT>, ACCOUNT> accountFunction) {
final Function<BonsaiValue<BonsaiAccount>, BonsaiAccount> bonsaiAccountFunction) {
try { try {
final BonsaiValue<BonsaiAccount> bonsaiValue = accountsToUpdate.get(address); final DiffBasedValue<ACCOUNT> diffBasedValue = accountsToUpdate.get(address);
if (bonsaiValue == null) { if (diffBasedValue == null) {
final Account account; final Account account;
if (wrappedWorldView() if (wrappedWorldView() instanceof DiffBasedWorldStateUpdateAccumulator) {
instanceof BonsaiWorldStateUpdateAccumulator bonsaiWorldStateUpdateAccumulator) { final DiffBasedWorldStateUpdateAccumulator<ACCOUNT> worldStateUpdateAccumulator =
account = bonsaiWorldStateUpdateAccumulator.loadAccount(address, bonsaiAccountFunction); (DiffBasedWorldStateUpdateAccumulator<ACCOUNT>) wrappedWorldView();
account = worldStateUpdateAccumulator.loadAccount(address, accountFunction);
} else { } else {
account = wrappedWorldView().get(address); account = wrappedWorldView().get(address);
} }
if (account instanceof BonsaiAccount bonsaiAccount) { if (account instanceof DiffBasedAccount diffBasedAccount) {
BonsaiAccount mutableAccount = new BonsaiAccount(bonsaiAccount, this, true); ACCOUNT mutableAccount = copyAccount((ACCOUNT) diffBasedAccount, this, true);
accountsToUpdate.put(address, new BonsaiValue<>(bonsaiAccount, mutableAccount)); accountsToUpdate.put(
address, new DiffBasedValue<>((ACCOUNT) diffBasedAccount, mutableAccount));
return mutableAccount; return mutableAccount;
} else { } else {
// add the empty read in accountsToUpdate // add the empty read in accountsToUpdate
accountsToUpdate.put(address, new BonsaiValue<>(null, null)); accountsToUpdate.put(address, new DiffBasedValue<>(null, null));
return null; return null;
} }
} else { } else {
return bonsaiAccountFunction.apply(bonsaiValue); return accountFunction.apply(diffBasedValue);
} }
} catch (MerkleTrieException e) { } catch (MerkleTrieException e) {
// need to throw to trigger the heal // need to throw to trigger the heal
@ -229,12 +235,12 @@ public class BonsaiWorldStateUpdateAccumulator
public void commit() { public void commit() {
this.isAccumulatorStateChanged = true; this.isAccumulatorStateChanged = true;
for (final Address deletedAddress : getDeletedAccounts()) { for (final Address deletedAddress : getDeletedAccounts()) {
final BonsaiValue<BonsaiAccount> accountValue = final DiffBasedValue<ACCOUNT> accountValue =
accountsToUpdate.computeIfAbsent( accountsToUpdate.computeIfAbsent(
deletedAddress, deletedAddress,
__ -> loadAccountFromParent(deletedAddress, new BonsaiValue<>(null, null, true))); __ -> loadAccountFromParent(deletedAddress, new DiffBasedValue<>(null, null, true)));
storageToClear.add(deletedAddress); storageToClear.add(deletedAddress);
final BonsaiValue<Bytes> codeValue = codeToUpdate.get(deletedAddress); final DiffBasedValue<Bytes> codeValue = codeToUpdate.get(deletedAddress);
if (codeValue != null) { if (codeValue != null) {
codeValue.setUpdated(null).setCleared(); codeValue.setUpdated(null).setCleared();
} else { } else {
@ -242,26 +248,27 @@ public class BonsaiWorldStateUpdateAccumulator
.getCode( .getCode(
deletedAddress, deletedAddress,
Optional.ofNullable(accountValue) Optional.ofNullable(accountValue)
.map(BonsaiValue::getPrior) .map(DiffBasedValue::getPrior)
.map(BonsaiAccount::getCodeHash) .map(DiffBasedAccount::getCodeHash)
.orElse(Hash.EMPTY)) .orElse(Hash.EMPTY))
.ifPresent( .ifPresent(
deletedCode -> deletedCode ->
codeToUpdate.put(deletedAddress, new BonsaiValue<>(deletedCode, null, true))); codeToUpdate.put(
deletedAddress, new DiffBasedValue<>(deletedCode, null, true)));
} }
// mark all updated storage as to be cleared // mark all updated storage as to be cleared
final Map<StorageSlotKey, BonsaiValue<UInt256>> deletedStorageUpdates = final Map<StorageSlotKey, DiffBasedValue<UInt256>> deletedStorageUpdates =
storageToUpdate.computeIfAbsent( storageToUpdate.computeIfAbsent(
deletedAddress, deletedAddress,
k -> k ->
new StorageConsumingMap<>( new StorageConsumingMap<>(
deletedAddress, new ConcurrentHashMap<>(), storagePreloader)); deletedAddress, new ConcurrentHashMap<>(), storagePreloader));
final Iterator<Map.Entry<StorageSlotKey, BonsaiValue<UInt256>>> iter = final Iterator<Map.Entry<StorageSlotKey, DiffBasedValue<UInt256>>> iter =
deletedStorageUpdates.entrySet().iterator(); deletedStorageUpdates.entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
final Map.Entry<StorageSlotKey, BonsaiValue<UInt256>> updateEntry = iter.next(); final Map.Entry<StorageSlotKey, DiffBasedValue<UInt256>> updateEntry = iter.next();
final BonsaiValue<UInt256> updatedSlot = updateEntry.getValue(); final DiffBasedValue<UInt256> updatedSlot = updateEntry.getValue();
if (updatedSlot.getPrior() == null || updatedSlot.getPrior().isZero()) { if (updatedSlot.getPrior() == null || updatedSlot.getPrior().isZero()) {
iter.remove(); iter.remove();
} else { } else {
@ -269,7 +276,7 @@ public class BonsaiWorldStateUpdateAccumulator
} }
} }
final BonsaiAccount originalValue = accountValue.getPrior(); final ACCOUNT originalValue = accountValue.getPrior();
if (originalValue != null) { if (originalValue != null) {
// Enumerate and delete addresses not updated // Enumerate and delete addresses not updated
wrappedWorldView() wrappedWorldView()
@ -280,7 +287,8 @@ public class BonsaiWorldStateUpdateAccumulator
new StorageSlotKey(Hash.wrap(keyHash), Optional.empty()); new StorageSlotKey(Hash.wrap(keyHash), Optional.empty());
if (!deletedStorageUpdates.containsKey(storageSlotKey)) { if (!deletedStorageUpdates.containsKey(storageSlotKey)) {
final UInt256 value = UInt256.fromBytes(RLP.decodeOne(entryValue)); final UInt256 value = UInt256.fromBytes(RLP.decodeOne(entryValue));
deletedStorageUpdates.put(storageSlotKey, new BonsaiValue<>(value, null, true)); deletedStorageUpdates.put(
storageSlotKey, new DiffBasedValue<>(value, null, true));
} }
}); });
} }
@ -294,11 +302,11 @@ public class BonsaiWorldStateUpdateAccumulator
.forEach( .forEach(
tracked -> { tracked -> {
final Address updatedAddress = tracked.getAddress(); final Address updatedAddress = tracked.getAddress();
final BonsaiAccount updatedAccount; final ACCOUNT updatedAccount;
final BonsaiValue<BonsaiAccount> updatedAccountValue = final DiffBasedValue<ACCOUNT> updatedAccountValue =
accountsToUpdate.get(updatedAddress); accountsToUpdate.get(updatedAddress);
final Map<StorageSlotKey, BonsaiValue<UInt256>> pendingStorageUpdates = final Map<StorageSlotKey, DiffBasedValue<UInt256>> pendingStorageUpdates =
storageToUpdate.computeIfAbsent( storageToUpdate.computeIfAbsent(
updatedAddress, updatedAddress,
k -> k ->
@ -311,12 +319,12 @@ public class BonsaiWorldStateUpdateAccumulator
} }
if (tracked.getWrappedAccount() == null) { if (tracked.getWrappedAccount() == null) {
updatedAccount = new BonsaiAccount(this, tracked); updatedAccount = createAccount(this, tracked);
tracked.setWrappedAccount(updatedAccount); tracked.setWrappedAccount(updatedAccount);
if (updatedAccountValue == null) { if (updatedAccountValue == null) {
accountsToUpdate.put(updatedAddress, new BonsaiValue<>(null, updatedAccount)); accountsToUpdate.put(updatedAddress, new DiffBasedValue<>(null, updatedAccount));
codeToUpdate.put( codeToUpdate.put(
updatedAddress, new BonsaiValue<>(null, updatedAccount.getCode())); updatedAddress, new DiffBasedValue<>(null, updatedAccount.getCode()));
} else { } else {
updatedAccountValue.setUpdated(updatedAccount); updatedAccountValue.setUpdated(updatedAccount);
} }
@ -334,17 +342,17 @@ public class BonsaiWorldStateUpdateAccumulator
} }
if (tracked.codeWasUpdated()) { if (tracked.codeWasUpdated()) {
final BonsaiValue<Bytes> pendingCode = final DiffBasedValue<Bytes> pendingCode =
codeToUpdate.computeIfAbsent( codeToUpdate.computeIfAbsent(
updatedAddress, updatedAddress,
addr -> addr ->
new BonsaiValue<>( new DiffBasedValue<>(
wrappedWorldView() wrappedWorldView()
.getCode( .getCode(
addr, addr,
Optional.ofNullable(updatedAccountValue) Optional.ofNullable(updatedAccountValue)
.map(BonsaiValue::getPrior) .map(DiffBasedValue::getPrior)
.map(BonsaiAccount::getCodeHash) .map(DiffBasedAccount::getCodeHash)
.orElse(Hash.EMPTY)) .orElse(Hash.EMPTY))
.orElse(null), .orElse(null),
null)); null));
@ -368,12 +376,11 @@ public class BonsaiWorldStateUpdateAccumulator
final StorageSlotKey slotKey = final StorageSlotKey slotKey =
new StorageSlotKey(hashAndSaveSlotPreImage(keyUInt), Optional.of(keyUInt)); new StorageSlotKey(hashAndSaveSlotPreImage(keyUInt), Optional.of(keyUInt));
final UInt256 value = storageUpdate.getValue(); final UInt256 value = storageUpdate.getValue();
final BonsaiValue<UInt256> pendingValue = pendingStorageUpdates.get(slotKey); final DiffBasedValue<UInt256> pendingValue = pendingStorageUpdates.get(slotKey);
if (pendingValue == null) { if (pendingValue == null) {
pendingStorageUpdates.put( pendingStorageUpdates.put(
slotKey, slotKey,
new BonsaiValue<>( new DiffBasedValue<>(
updatedAccount.getOriginalStorageValue(keyUInt), value)); updatedAccount.getOriginalStorageValue(keyUInt), value));
} else { } else {
pendingValue.setUpdated(value); pendingValue.setUpdated(value);
@ -394,7 +401,7 @@ public class BonsaiWorldStateUpdateAccumulator
@Override @Override
public Optional<Bytes> getCode(final Address address, final Hash codeHash) { public Optional<Bytes> getCode(final Address address, final Hash codeHash) {
final BonsaiValue<Bytes> localCode = codeToUpdate.get(address); final DiffBasedValue<Bytes> localCode = codeToUpdate.get(address);
if (localCode == null) { if (localCode == null) {
final Optional<Bytes> code = wrappedWorldView().getCode(address, codeHash); final Optional<Bytes> code = wrappedWorldView().getCode(address, codeHash);
if (code.isEmpty() && !codeHash.equals(Hash.EMPTY)) { if (code.isEmpty() && !codeHash.equals(Hash.EMPTY)) {
@ -417,31 +424,26 @@ public class BonsaiWorldStateUpdateAccumulator
@Override @Override
public Optional<UInt256> getStorageValueByStorageSlotKey( public Optional<UInt256> getStorageValueByStorageSlotKey(
final Address address, final StorageSlotKey storageSlotKey) { final Address address, final StorageSlotKey storageSlotKey) {
final Map<StorageSlotKey, BonsaiValue<UInt256>> localAccountStorage = final Map<StorageSlotKey, DiffBasedValue<UInt256>> localAccountStorage =
storageToUpdate.get(address); storageToUpdate.get(address);
if (localAccountStorage != null) { if (localAccountStorage != null) {
final BonsaiValue<UInt256> value = localAccountStorage.get(storageSlotKey); final DiffBasedValue<UInt256> value = localAccountStorage.get(storageSlotKey);
if (value != null) { if (value != null) {
return Optional.ofNullable(value.getUpdated()); return Optional.ofNullable(value.getUpdated());
} }
} }
try { try {
final Optional<UInt256> valueUInt = final Optional<UInt256> valueUInt =
(wrappedWorldView() instanceof BonsaiWorldState bonsaiWorldState) (wrappedWorldView() instanceof DiffBasedWorldState worldState)
? bonsaiWorldState.getStorageValueByStorageSlotKey( ? worldState.getStorageValueByStorageSlotKey(address, storageSlotKey)
() ->
Optional.ofNullable(loadAccount(address, BonsaiValue::getPrior))
.map(BonsaiAccount::getStorageRoot),
address,
storageSlotKey)
: wrappedWorldView().getStorageValueByStorageSlotKey(address, storageSlotKey); : wrappedWorldView().getStorageValueByStorageSlotKey(address, storageSlotKey);
storageToUpdate storageToUpdate
.computeIfAbsent( .computeIfAbsent(
address, address,
key -> key ->
new StorageConsumingMap<>(address, new ConcurrentHashMap<>(), storagePreloader)) new StorageConsumingMap<>(address, new ConcurrentHashMap<>(), storagePreloader))
.put(storageSlotKey, new BonsaiValue<>(valueUInt.orElse(null), valueUInt.orElse(null))); .put(
storageSlotKey, new DiffBasedValue<>(valueUInt.orElse(null), valueUInt.orElse(null)));
return valueUInt; return valueUInt;
} catch (MerkleTrieException e) { } catch (MerkleTrieException e) {
// need to throw to trigger the heal // need to throw to trigger the heal
@ -455,10 +457,10 @@ public class BonsaiWorldStateUpdateAccumulator
// TODO maybe log the read into the trie layer? // TODO maybe log the read into the trie layer?
StorageSlotKey storageSlotKey = StorageSlotKey storageSlotKey =
new StorageSlotKey(hashAndSaveSlotPreImage(storageKey), Optional.of(storageKey)); new StorageSlotKey(hashAndSaveSlotPreImage(storageKey), Optional.of(storageKey));
final Map<StorageSlotKey, BonsaiValue<UInt256>> localAccountStorage = final Map<StorageSlotKey, DiffBasedValue<UInt256>> localAccountStorage =
storageToUpdate.get(address); storageToUpdate.get(address);
if (localAccountStorage != null) { if (localAccountStorage != null) {
final BonsaiValue<UInt256> value = localAccountStorage.get(storageSlotKey); final DiffBasedValue<UInt256> value = localAccountStorage.get(storageSlotKey);
if (value != null) { if (value != null) {
if (value.isLastStepCleared()) { if (value.isLastStepCleared()) {
return UInt256.ZERO; return UInt256.ZERO;
@ -482,11 +484,11 @@ public class BonsaiWorldStateUpdateAccumulator
@Override @Override
public Map<Bytes32, Bytes> getAllAccountStorage(final Address address, final Hash rootHash) { public Map<Bytes32, Bytes> getAllAccountStorage(final Address address, final Hash rootHash) {
final Map<Bytes32, Bytes> results = wrappedWorldView().getAllAccountStorage(address, rootHash); final Map<Bytes32, Bytes> results = wrappedWorldView().getAllAccountStorage(address, rootHash);
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> bonsaiValueStorage = final StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>> diffBasedValueStorage =
storageToUpdate.get(address); storageToUpdate.get(address);
if (bonsaiValueStorage != null) { if (diffBasedValueStorage != null) {
// hash the key to match the implied storage interface of hashed slotKey // hash the key to match the implied storage interface of hashed slotKey
bonsaiValueStorage.forEach( diffBasedValueStorage.forEach(
(key, value) -> results.put(key.getSlotHash(), value.getUpdated())); (key, value) -> results.put(key.getSlotHash(), value.getUpdated()));
} }
return results; return results;
@ -498,7 +500,7 @@ public class BonsaiWorldStateUpdateAccumulator
} }
@Override @Override
public BonsaiWorldStateKeyValueStorage getWorldStateStorage() { public DiffBasedWorldStateKeyValueStorage getWorldStateStorage() {
return wrappedWorldView().getWorldStateStorage(); return wrappedWorldView().getWorldStateStorage();
} }
@ -550,7 +552,7 @@ public class BonsaiWorldStateUpdateAccumulator
// non-change, a cached read. // non-change, a cached read.
return; return;
} }
BonsaiValue<BonsaiAccount> accountValue = accountsToUpdate.get(address); DiffBasedValue<ACCOUNT> accountValue = accountsToUpdate.get(address);
if (accountValue == null) { if (accountValue == null) {
accountValue = loadAccountFromParent(address, accountValue); accountValue = loadAccountFromParent(address, accountValue);
} }
@ -558,7 +560,7 @@ public class BonsaiWorldStateUpdateAccumulator
if (expectedValue == null && replacementValue != null) { if (expectedValue == null && replacementValue != null) {
accountsToUpdate.put( accountsToUpdate.put(
address, address,
new BonsaiValue<>(null, new BonsaiAccount(this, address, replacementValue, true))); new DiffBasedValue<>(null, createAccount(this, address, replacementValue, true)));
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
String.format( String.format(
@ -572,7 +574,7 @@ public class BonsaiWorldStateUpdateAccumulator
"Expected to create account, but the account exists. Address=%s", address)); "Expected to create account, but the account exists. Address=%s", address));
} }
} else { } else {
BonsaiAccount.assertCloseEnoughForDiffing( assertCloseEnoughForDiffing(
accountValue.getUpdated(), accountValue.getUpdated(),
expectedValue, expectedValue,
"Address=" + address + " Prior Value in Rolling Change"); "Address=" + address + " Prior Value in Rolling Change");
@ -586,19 +588,18 @@ public class BonsaiWorldStateUpdateAccumulator
accountValue.setUpdated(null); accountValue.setUpdated(null);
} }
} else { } else {
accountValue.setUpdated( accountValue.setUpdated(createAccount(wrappedWorldView(), address, replacementValue, true));
new BonsaiAccount(wrappedWorldView(), address, replacementValue, true));
} }
} }
} }
private BonsaiValue<BonsaiAccount> loadAccountFromParent( private DiffBasedValue<ACCOUNT> loadAccountFromParent(
final Address address, final BonsaiValue<BonsaiAccount> defaultValue) { final Address address, final DiffBasedValue<ACCOUNT> defaultValue) {
try { try {
final Account parentAccount = wrappedWorldView().get(address); final Account parentAccount = wrappedWorldView().get(address);
if (parentAccount instanceof BonsaiAccount account) { if (parentAccount instanceof DiffBasedAccount account) {
final BonsaiValue<BonsaiAccount> loadedAccountValue = final DiffBasedValue<ACCOUNT> loadedAccountValue =
new BonsaiValue<>(new BonsaiAccount(account), account); new DiffBasedValue<>(copyAccount((ACCOUNT) account), ((ACCOUNT) account));
accountsToUpdate.put(address, loadedAccountValue); accountsToUpdate.put(address, loadedAccountValue);
return loadedAccountValue; return loadedAccountValue;
} else { } else {
@ -617,7 +618,7 @@ public class BonsaiWorldStateUpdateAccumulator
// non-change, a cached read. // non-change, a cached read.
return; return;
} }
BonsaiValue<Bytes> codeValue = codeToUpdate.get(address); DiffBasedValue<Bytes> codeValue = codeToUpdate.get(address);
if (codeValue == null) { if (codeValue == null) {
final Bytes storedCode = final Bytes storedCode =
wrappedWorldView() wrappedWorldView()
@ -625,14 +626,14 @@ public class BonsaiWorldStateUpdateAccumulator
address, Optional.ofNullable(expectedCode).map(Hash::hash).orElse(Hash.EMPTY)) address, Optional.ofNullable(expectedCode).map(Hash::hash).orElse(Hash.EMPTY))
.orElse(Bytes.EMPTY); .orElse(Bytes.EMPTY);
if (!storedCode.isEmpty()) { if (!storedCode.isEmpty()) {
codeValue = new BonsaiValue<>(storedCode, storedCode); codeValue = new DiffBasedValue<>(storedCode, storedCode);
codeToUpdate.put(address, codeValue); codeToUpdate.put(address, codeValue);
} }
} }
if (codeValue == null) { if (codeValue == null) {
if ((expectedCode == null || expectedCode.isEmpty()) && replacementCode != null) { if ((expectedCode == null || expectedCode.isEmpty()) && replacementCode != null) {
codeToUpdate.put(address, new BonsaiValue<>(null, replacementCode)); codeToUpdate.put(address, new DiffBasedValue<>(null, replacementCode));
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
String.format( String.format(
@ -660,10 +661,10 @@ public class BonsaiWorldStateUpdateAccumulator
} }
} }
private Map<StorageSlotKey, BonsaiValue<UInt256>> maybeCreateStorageMap( private Map<StorageSlotKey, DiffBasedValue<UInt256>> maybeCreateStorageMap(
final Map<StorageSlotKey, BonsaiValue<UInt256>> storageMap, final Address address) { final Map<StorageSlotKey, DiffBasedValue<UInt256>> storageMap, final Address address) {
if (storageMap == null) { if (storageMap == null) {
final StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> newMap = final StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>> newMap =
new StorageConsumingMap<>(address, new ConcurrentHashMap<>(), storagePreloader); new StorageConsumingMap<>(address, new ConcurrentHashMap<>(), storagePreloader);
storageToUpdate.put(address, newMap); storageToUpdate.put(address, newMap);
return newMap; return newMap;
@ -685,13 +686,13 @@ public class BonsaiWorldStateUpdateAccumulator
// corner case on deletes, non-change // corner case on deletes, non-change
return; return;
} }
final Map<StorageSlotKey, BonsaiValue<UInt256>> storageMap = storageToUpdate.get(address); final Map<StorageSlotKey, DiffBasedValue<UInt256>> storageMap = storageToUpdate.get(address);
BonsaiValue<UInt256> slotValue = storageMap == null ? null : storageMap.get(storageSlotKey); DiffBasedValue<UInt256> slotValue = storageMap == null ? null : storageMap.get(storageSlotKey);
if (slotValue == null) { if (slotValue == null) {
final Optional<UInt256> storageValue = final Optional<UInt256> storageValue =
wrappedWorldView().getStorageValueByStorageSlotKey(address, storageSlotKey); wrappedWorldView().getStorageValueByStorageSlotKey(address, storageSlotKey);
if (storageValue.isPresent()) { if (storageValue.isPresent()) {
slotValue = new BonsaiValue<>(storageValue.get(), storageValue.get()); slotValue = new DiffBasedValue<>(storageValue.get(), storageValue.get());
storageToUpdate storageToUpdate
.computeIfAbsent( .computeIfAbsent(
address, address,
@ -703,7 +704,7 @@ public class BonsaiWorldStateUpdateAccumulator
if (slotValue == null) { if (slotValue == null) {
if ((expectedValue == null || expectedValue.isZero()) && replacementValue != null) { if ((expectedValue == null || expectedValue.isZero()) && replacementValue != null) {
maybeCreateStorageMap(storageMap, address) maybeCreateStorageMap(storageMap, address)
.put(storageSlotKey, new BonsaiValue<>(null, replacementValue)); .put(storageSlotKey, new DiffBasedValue<>(null, replacementValue));
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
String.format( String.format(
@ -730,7 +731,7 @@ public class BonsaiWorldStateUpdateAccumulator
existingSlotValue == null ? "null" : existingSlotValue.toShortHexString())); existingSlotValue == null ? "null" : existingSlotValue.toShortHexString()));
} }
if (replacementValue == null && slotValue.getPrior() == null) { if (replacementValue == null && slotValue.getPrior() == null) {
final Map<StorageSlotKey, BonsaiValue<UInt256>> thisStorageUpdate = final Map<StorageSlotKey, DiffBasedValue<UInt256>> thisStorageUpdate =
maybeCreateStorageMap(storageMap, address); maybeCreateStorageMap(storageMap, address);
thisStorageUpdate.remove(storageSlotKey); thisStorageUpdate.remove(storageSlotKey);
if (thisStorageUpdate.isEmpty()) { if (thisStorageUpdate.isEmpty()) {
@ -769,67 +770,6 @@ public class BonsaiWorldStateUpdateAccumulator
storageKeyHashLookup.clear(); storageKeyHashLookup.clear();
} }
public static class AccountConsumingMap<T> extends ForwardingMap<Address, T> {
private final ConcurrentMap<Address, T> accounts;
private final Consumer<T> consumer;
public AccountConsumingMap(
final ConcurrentMap<Address, T> accounts, final Consumer<T> consumer) {
this.accounts = accounts;
this.consumer = consumer;
}
@Override
public T put(@Nonnull final Address address, @Nonnull final T value) {
consumer.process(address, value);
return accounts.put(address, value);
}
public Consumer<T> getConsumer() {
return consumer;
}
@Override
protected Map<Address, T> delegate() {
return accounts;
}
}
public static class StorageConsumingMap<K, T> extends ForwardingMap<K, T> {
private final Address address;
private final ConcurrentMap<K, T> storages;
private final Consumer<K> consumer;
public StorageConsumingMap(
final Address address, final ConcurrentMap<K, T> storages, final Consumer<K> consumer) {
this.address = address;
this.storages = storages;
this.consumer = consumer;
}
@Override
public T put(@Nonnull final K slotKey, @Nonnull final T value) {
consumer.process(address, slotKey);
return storages.put(slotKey, value);
}
public Consumer<K> getConsumer() {
return consumer;
}
@Override
protected Map<K, T> delegate() {
return storages;
}
}
public interface Consumer<T> {
void process(final Address address, T value);
}
protected Hash hashAndSaveAccountPreImage(final Address address) { protected Hash hashAndSaveAccountPreImage(final Address address) {
// no need to save account preimage by default // no need to save account preimage by default
return Hash.hash(address); return Hash.hash(address);
@ -843,4 +783,33 @@ public class BonsaiWorldStateUpdateAccumulator
} }
return hash; return hash;
} }
public abstract DiffBasedWorldStateUpdateAccumulator<ACCOUNT> copy();
protected abstract ACCOUNT copyAccount(final ACCOUNT account);
protected abstract ACCOUNT copyAccount(
final ACCOUNT toCopy, final DiffBasedWorldView context, final boolean mutable);
protected abstract ACCOUNT createAccount(
final DiffBasedWorldView context,
final Address address,
final AccountValue stateTrieAccount,
final boolean mutable);
protected abstract ACCOUNT createAccount(
final DiffBasedWorldView context,
final Address address,
final Hash addressHash,
final long nonce,
final Wei balance,
final Hash storageRoot,
final Hash codeHash,
final boolean mutable);
protected abstract ACCOUNT createAccount(
final DiffBasedWorldView context, final UpdateTrackingAccount<ACCOUNT> tracked);
protected abstract void assertCloseEnoughForDiffing(
final ACCOUNT source, final AccountValue account, final String context);
} }

@ -0,0 +1,49 @@
/*
* 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.trie.diffbased.common.worldview.accumulator.preload;
import org.hyperledger.besu.datatypes.Address;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import com.google.common.collect.ForwardingMap;
public class AccountConsumingMap<T> extends ForwardingMap<Address, T> {
private final ConcurrentMap<Address, T> accounts;
private final Consumer<T> consumer;
public AccountConsumingMap(final ConcurrentMap<Address, T> accounts, final Consumer<T> consumer) {
this.accounts = accounts;
this.consumer = consumer;
}
@Override
public T put(@Nonnull final Address address, @Nonnull final T value) {
consumer.process(address, value);
return accounts.put(address, value);
}
public Consumer<T> getConsumer() {
return consumer;
}
@Override
protected Map<Address, T> delegate() {
return accounts;
}
}

@ -0,0 +1,21 @@
/*
* 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.trie.diffbased.common.worldview.accumulator.preload;
import org.hyperledger.besu.datatypes.Address;
public interface Consumer<T> {
void process(final Address address, T value);
}

@ -0,0 +1,53 @@
/*
* 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.trie.diffbased.common.worldview.accumulator.preload;
import org.hyperledger.besu.datatypes.Address;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import com.google.common.collect.ForwardingMap;
public class StorageConsumingMap<K, T> extends ForwardingMap<K, T> {
private final Address address;
private final ConcurrentMap<K, T> storages;
private final Consumer<K> consumer;
public StorageConsumingMap(
final Address address, final ConcurrentMap<K, T> storages, final Consumer<K> consumer) {
this.address = address;
this.storages = storages;
this.consumer = consumer;
}
@Override
public T put(@Nonnull final K slotKey, @Nonnull final T value) {
consumer.process(address, slotKey);
return storages.put(slotKey, value);
}
public Consumer<K> getConsumer() {
return consumer;
}
@Override
protected Map<K, T> delegate() {
return storages;
}
}

@ -15,7 +15,7 @@
package org.hyperledger.besu.ethereum.worldstate; package org.hyperledger.besu.ethereum.worldstate;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;

@ -25,9 +25,9 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKey
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage;
import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState; import org.hyperledger.besu.ethereum.trie.forest.worldview.ForestMutableWorldState;
@ -95,15 +95,15 @@ public class InMemoryKeyValueStorageProvider extends KeyValueStorageProvider {
final Blockchain blockchain, final EvmConfiguration evmConfiguration) { final Blockchain blockchain, final EvmConfiguration evmConfiguration) {
final InMemoryKeyValueStorageProvider inMemoryKeyValueStorageProvider = final InMemoryKeyValueStorageProvider inMemoryKeyValueStorageProvider =
new InMemoryKeyValueStorageProvider(); new InMemoryKeyValueStorageProvider();
final CachedMerkleTrieLoader cachedMerkleTrieLoader = final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader =
new CachedMerkleTrieLoader(new NoOpMetricsSystem()); new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem());
return new BonsaiWorldStateProvider( return new BonsaiWorldStateProvider(
(BonsaiWorldStateKeyValueStorage) (BonsaiWorldStateKeyValueStorage)
inMemoryKeyValueStorageProvider.createWorldStateStorage( inMemoryKeyValueStorageProvider.createWorldStateStorage(
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG),
blockchain, blockchain,
Optional.empty(), Optional.empty(),
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
null, null,
evmConfiguration); evmConfiguration);
} }

@ -20,7 +20,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -41,9 +41,9 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -66,8 +66,8 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -159,7 +159,7 @@ public abstract class AbstractIsolationTests {
(BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage, (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage,
blockchain, blockchain,
Optional.of(16L), Optional.of(16L),
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
null, null,
EvmConfiguration.DEFAULT); EvmConfiguration.DEFAULT);
var ws = archive.getMutable(); var ws = archive.getMutable();

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -26,8 +26,8 @@ import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
@ -45,9 +45,9 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
class CachedMerkleTrieLoaderTest { class BonsaiCachedMerkleTrieLoaderTest {
private CachedMerkleTrieLoader merkleTrieLoader; private BonsaiCachedMerkleTrieLoader merkleTrieLoader;
private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider(); private final StorageProvider storageProvider = new InMemoryKeyValueStorageProvider();
private final BonsaiWorldStateKeyValueStorage inMemoryWorldState = private final BonsaiWorldStateKeyValueStorage inMemoryWorldState =
Mockito.spy( Mockito.spy(
@ -69,7 +69,7 @@ class CachedMerkleTrieLoaderTest {
TrieGenerator.generateTrie( TrieGenerator.generateTrie(
worldStateStorageCoordinator, worldStateStorageCoordinator,
accounts.stream().map(Address::addressHash).collect(Collectors.toList())); accounts.stream().map(Address::addressHash).collect(Collectors.toList()));
merkleTrieLoader = new CachedMerkleTrieLoader(new NoOpMetricsSystem()); merkleTrieLoader = new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem());
} }
@Test @Test

@ -14,7 +14,7 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@ -13,13 +13,13 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.BLOCKCHAIN; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.BLOCKCHAIN;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import static org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY; import static org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage.WORLD_BLOCK_HASH_KEY;
import static org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY; import static org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@ -36,13 +36,13 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
@ -77,7 +77,7 @@ class BonsaiWorldStateProviderTest {
@Mock SegmentedKeyValueStorageTransaction segmentedKeyValueStorageTransaction; @Mock SegmentedKeyValueStorageTransaction segmentedKeyValueStorageTransaction;
BonsaiWorldStateProvider bonsaiWorldStateArchive; BonsaiWorldStateProvider bonsaiWorldStateArchive;
@Mock CachedWorldStorageManager cachedWorldStorageManager; @Mock BonsaiCachedWorldStorageManager cachedWorldStorageManager;
@Mock TrieLogManager trieLogManager; @Mock TrieLogManager trieLogManager;
@BeforeEach @BeforeEach
@ -111,7 +111,7 @@ class BonsaiWorldStateProviderTest {
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG),
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT); EvmConfiguration.DEFAULT);
assertThat(bonsaiWorldStateArchive.getMutable(chainHead, true)) assertThat(bonsaiWorldStateArchive.getMutable(chainHead, true))
@ -128,7 +128,7 @@ class BonsaiWorldStateProviderTest {
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG),
blockchain, blockchain,
Optional.of(512L), Optional.of(512L),
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
null, null,
EvmConfiguration.DEFAULT); EvmConfiguration.DEFAULT);
final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader();
@ -150,7 +150,7 @@ class BonsaiWorldStateProviderTest {
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG),
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT); EvmConfiguration.DEFAULT);
final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader();
final BlockHeader chainHead = blockBuilder.number(511).buildHeader(); final BlockHeader chainHead = blockBuilder.number(511).buildHeader();
@ -185,7 +185,7 @@ class BonsaiWorldStateProviderTest {
trieLogManager, trieLogManager,
worldStateKeyValueStorage, worldStateKeyValueStorage,
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT)); EvmConfiguration.DEFAULT));
final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader();
@ -214,7 +214,7 @@ class BonsaiWorldStateProviderTest {
trieLogManager, trieLogManager,
worldStateKeyValueStorage, worldStateKeyValueStorage,
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT)); EvmConfiguration.DEFAULT));
final BlockHeader blockHeader = blockBuilder.number(0).buildHeader(); final BlockHeader blockHeader = blockBuilder.number(0).buildHeader();
@ -254,7 +254,7 @@ class BonsaiWorldStateProviderTest {
trieLogManager, trieLogManager,
worldStateKeyValueStorage, worldStateKeyValueStorage,
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT)); EvmConfiguration.DEFAULT));
// initial persisted state hash key // initial persisted state hash key
@ -297,7 +297,7 @@ class BonsaiWorldStateProviderTest {
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG), DataStorageConfiguration.DEFAULT_BONSAI_CONFIG),
blockchain, blockchain,
new CachedMerkleTrieLoader(new NoOpMetricsSystem()), new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()),
EvmConfiguration.DEFAULT)); EvmConfiguration.DEFAULT));
// initial persisted state hash key // initial persisted state hash key

@ -14,7 +14,7 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -29,11 +29,11 @@ import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;

@ -14,7 +14,7 @@
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.ACCOUNT_INFO_STATE;
@ -25,11 +25,11 @@ import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIden
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogFactoryImpl; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog.TrieLogFactoryImpl;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;

@ -12,11 +12,11 @@
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE; import static org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier.TRIE_BRANCH_STORAGE;
import static org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY; import static org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage.WORLD_ROOT_HASH_KEY;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@ -24,6 +24,7 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.plugin.services.trielogs.TrieLog; import org.hyperledger.besu.plugin.services.trielogs.TrieLog;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
@ -22,9 +22,10 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.trielog;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -26,7 +26,10 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogAddedEvent;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer;
import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogPruner;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.worldview; package org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
@ -23,8 +23,8 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.util.HashMap; import java.util.HashMap;
@ -69,8 +69,8 @@ class BonsaiWorldStateTest {
@MethodSource("priorAndUpdatedEmptyAndNullBytes") @MethodSource("priorAndUpdatedEmptyAndNullBytes")
void codeUpdateDoesNothingWhenMarkedAsDeletedButAlreadyDeleted( void codeUpdateDoesNothingWhenMarkedAsDeletedButAlreadyDeleted(
final Bytes prior, final Bytes updated) { final Bytes prior, final Bytes updated) {
final Map<Address, BonsaiValue<Bytes>> codeToUpdate = final Map<Address, DiffBasedValue<Bytes>> codeToUpdate =
Map.of(Address.ZERO, new BonsaiValue<>(prior, updated)); Map.of(Address.ZERO, new DiffBasedValue<>(prior, updated));
when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate); when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate);
worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator); worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator);
@ -79,8 +79,8 @@ class BonsaiWorldStateTest {
@Test @Test
void codeUpdateDoesNothingWhenAddingSameAsExistingValue() { void codeUpdateDoesNothingWhenAddingSameAsExistingValue() {
final Map<Address, BonsaiValue<Bytes>> codeToUpdate = final Map<Address, DiffBasedValue<Bytes>> codeToUpdate =
Map.of(Address.ZERO, new BonsaiValue<>(CODE, CODE)); Map.of(Address.ZERO, new DiffBasedValue<>(CODE, CODE));
when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate); when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate);
worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator); worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator);
@ -90,8 +90,8 @@ class BonsaiWorldStateTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("emptyAndNullBytes") @MethodSource("emptyAndNullBytes")
void removesCodeWhenMarkedAsDeleted(final Bytes updated) { void removesCodeWhenMarkedAsDeleted(final Bytes updated) {
final Map<Address, BonsaiValue<Bytes>> codeToUpdate = final Map<Address, DiffBasedValue<Bytes>> codeToUpdate =
Map.of(Address.ZERO, new BonsaiValue<>(CODE, updated)); Map.of(Address.ZERO, new DiffBasedValue<>(CODE, updated));
when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate); when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate);
worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator); worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator);
@ -101,8 +101,8 @@ class BonsaiWorldStateTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("codeValueAndEmptyAndNullBytes") @MethodSource("codeValueAndEmptyAndNullBytes")
void addsCodeForNewCodeValue(final Bytes prior) { void addsCodeForNewCodeValue(final Bytes prior) {
final Map<Address, BonsaiValue<Bytes>> codeToUpdate = final Map<Address, DiffBasedValue<Bytes>> codeToUpdate =
Map.of(ACCOUNT, new BonsaiValue<>(prior, CODE)); Map.of(ACCOUNT, new DiffBasedValue<>(prior, CODE));
when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate); when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate);
worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator); worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator);
@ -112,10 +112,10 @@ class BonsaiWorldStateTest {
@Test @Test
void updateCodeForMultipleValues() { void updateCodeForMultipleValues() {
final Map<Address, BonsaiValue<Bytes>> codeToUpdate = new HashMap<>(); final Map<Address, DiffBasedValue<Bytes>> codeToUpdate = new HashMap<>();
codeToUpdate.put(Address.fromHexString("0x1"), new BonsaiValue<>(null, CODE)); codeToUpdate.put(Address.fromHexString("0x1"), new DiffBasedValue<>(null, CODE));
codeToUpdate.put(Address.fromHexString("0x2"), new BonsaiValue<>(CODE, null)); codeToUpdate.put(Address.fromHexString("0x2"), new DiffBasedValue<>(CODE, null));
codeToUpdate.put(Address.fromHexString("0x3"), new BonsaiValue<>(Bytes.of(9), CODE)); codeToUpdate.put(Address.fromHexString("0x3"), new DiffBasedValue<>(Bytes.of(9), CODE));
when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate); when(bonsaiWorldStateUpdateAccumulator.getCodeToUpdate()).thenReturn(codeToUpdate);
worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator); worldState.updateCode(Optional.of(bonsaiUpdater), bonsaiWorldStateUpdateAccumulator);

@ -13,13 +13,15 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.storage.flat; package org.hyperledger.besu.ethereum.trie.diffbased.common.storage.flat;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD; import static org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat.FullFlatDbStrategy;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.flat.PartialFlatDbStrategy;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;

@ -13,7 +13,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
* *
*/ */
package org.hyperledger.besu.ethereum.trie.bonsai.trielog; package org.hyperledger.besu.ethereum.trie.diffbased.common.trielog;
import org.hyperledger.besu.datatypes.AccountValue; import org.hyperledger.besu.datatypes.AccountValue;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;

@ -66,6 +66,7 @@ public class ForestKeyValueStorageWorldStateStorageTest {
storage.updater().putCode(MerkleTrie.EMPTY_TRIE_NODE).putCode(Bytes.EMPTY).commit(); storage.updater().putCode(MerkleTrie.EMPTY_TRIE_NODE).putCode(Bytes.EMPTY).commit();
assertThat(storage.getCode(Hash.EMPTY_TRIE_HASH)).contains(MerkleTrie.EMPTY_TRIE_NODE); assertThat(storage.getCode(Hash.EMPTY_TRIE_HASH)).contains(MerkleTrie.EMPTY_TRIE_NODE);
assertThat(storage.getCode(Hash.EMPTY)).contains(Bytes.EMPTY); assertThat(storage.getCode(Hash.EMPTY)).contains(Bytes.EMPTY);
} }

@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.PendingBlocksManager;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiWorldStateProvider; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiWorldStateProvider;
import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner; import org.hyperledger.besu.ethereum.trie.forest.pruner.Pruner;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;

@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader;
import org.hyperledger.besu.ethereum.eth.sync.TrailingPeerRequirements; 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.StalledDownloadException;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;
import org.hyperledger.besu.services.tasks.TaskCollection; import org.hyperledger.besu.services.tasks.TaskCollection;

@ -20,7 +20,7 @@ import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.get
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; 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.eth.sync.snapsync.request.heal.TrieNodeHealingRequest;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.exception.StorageException;

@ -30,7 +30,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountFlatD
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.StorageFlatDatabaseHealingRangeRequest; 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.eth.sync.worldstate.WorldDownloadState;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -28,7 +28,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.AccountRangeDataR
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.metrics.BesuMetricCategory;
import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.trie.NodeUpdater; import org.hyperledger.besu.ethereum.trie.NodeUpdater;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.proof.WorldStateProofProvider;
import org.hyperledger.besu.ethereum.trie.CompactEncoding; import org.hyperledger.besu.ethereum.trie.CompactEncoding;
import org.hyperledger.besu.ethereum.trie.NodeUpdater; import org.hyperledger.besu.ethereum.trie.NodeUpdater;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.FlatDbMode; import org.hyperledger.besu.ethereum.worldstate.FlatDbMode;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -36,7 +36,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.Checkpoint;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint; import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.ImmutableCheckpoint;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.FastDownloaderFactory; import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.FastDownloaderFactory;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -34,7 +34,7 @@ import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.FastWorldState
import org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate.NodeDataRequest; 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.StalledDownloadException;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloader;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -26,7 +26,7 @@ import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.eth.manager.task.EthTask; import org.hyperledger.besu.ethereum.eth.manager.task.EthTask;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException; import org.hyperledger.besu.ethereum.eth.sync.worldstate.StalledDownloadException;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -22,7 +22,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory; import org.hyperledger.besu.ethereum.trie.patricia.StoredNodeFactory;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;

@ -25,7 +25,7 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.AccountRangeDataR
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.BytecodeRequest; 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.SnapDataRequest;
import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; 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.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;

@ -39,7 +39,7 @@ 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.SnapDataRequest;
import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldStateDownloadProcess;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -27,7 +27,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
@ -51,6 +51,7 @@ public class TaskGenerator {
new InMemoryKeyValueStorageProvider(), new InMemoryKeyValueStorageProvider(),
new NoOpMetricsSystem(), new NoOpMetricsSystem(),
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
final WorldStateStorageCoordinator worldStateStorageCoordinator = final WorldStateStorageCoordinator worldStateStorageCoordinator =
new WorldStateStorageCoordinator(worldStateKeyValueStorage); new WorldStateStorageCoordinator(worldStateKeyValueStorage);

@ -29,7 +29,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;

@ -31,7 +31,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.RangeManager; import org.hyperledger.besu.ethereum.trie.RangeManager;
import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector; import org.hyperledger.besu.ethereum.trie.RangeStorageEntriesCollector;
import org.hyperledger.besu.ethereum.trie.TrieIterator; import org.hyperledger.besu.ethereum.trie.TrieIterator;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
@ -89,7 +89,6 @@ class StorageFlatDatabaseHealingRangeRequestTest {
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG); DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage); worldStateStorageCoordinator = new WorldStateStorageCoordinator(worldStateKeyValueStorage);
proofProvider = new WorldStateProofProvider(worldStateStorageCoordinator); proofProvider = new WorldStateProofProvider(worldStateStorageCoordinator);
trie = trie =
TrieGenerator.generateTrie( TrieGenerator.generateTrie(
worldStateStorageCoordinator, worldStateStorageCoordinator,

@ -21,7 +21,7 @@ import org.hyperledger.besu.ethereum.core.TrieGenerator;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.storage.StorageProvider; import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.trie.MerkleTrie; import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue; import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;

@ -17,11 +17,13 @@ package org.hyperledger.besu.ethereum.referencetests;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.StorageSlotKey; import org.hyperledger.besu.datatypes.StorageSlotKey;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiValue; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiPreImageProxy;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiPreImageProxy; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldView; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.Consumer;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.preload.StorageConsumingMap;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -32,8 +34,8 @@ public class BonsaiReferenceTestUpdateAccumulator extends BonsaiWorldStateUpdate
private final BonsaiPreImageProxy preImageProxy; private final BonsaiPreImageProxy preImageProxy;
public BonsaiReferenceTestUpdateAccumulator( public BonsaiReferenceTestUpdateAccumulator(
final BonsaiWorldView world, final DiffBasedWorldView world,
final Consumer<BonsaiValue<BonsaiAccount>> accountPreloader, final Consumer<DiffBasedValue<BonsaiAccount>> accountPreloader,
final Consumer<StorageSlotKey> storagePreloader, final Consumer<StorageSlotKey> storagePreloader,
final BonsaiPreImageProxy preImageProxy, final BonsaiPreImageProxy preImageProxy,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
@ -65,7 +67,7 @@ public class BonsaiReferenceTestUpdateAccumulator extends BonsaiWorldStateUpdate
getStorageToUpdate() getStorageToUpdate()
.forEach( .forEach(
(k, v) -> { (k, v) -> {
StorageConsumingMap<StorageSlotKey, BonsaiValue<UInt256>> newMap = StorageConsumingMap<StorageSlotKey, DiffBasedValue<UInt256>> newMap =
new StorageConsumingMap<>(k, new ConcurrentHashMap<>(), v.getConsumer()); new StorageConsumingMap<>(k, new ConcurrentHashMap<>(), v.getConsumer());
v.forEach((key, value) -> newMap.put(key, value.copy())); v.forEach((key, value) -> newMap.put(key, value.copy()));
copy.getStorageToUpdate().put(k, newMap); copy.getStorageToUpdate().put(k, newMap);

@ -18,16 +18,18 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedMerkleTrieLoader; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.CachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoOpBonsaiCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.cache.NoOpCachedWorldStorageManager; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiPreImageProxy;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiPreImageProxy; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateLayerStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateLayerStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogAddedEvent; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.trie.bonsai.trielog.TrieLogManager; import org.hyperledger.besu.ethereum.trie.diffbased.common.cache.DiffBasedCachedWorldStorageManager;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogAddedEvent;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogManager;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -54,14 +56,14 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
protected BonsaiReferenceTestWorldState( protected BonsaiReferenceTestWorldState(
final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage, final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage,
final CachedMerkleTrieLoader cachedMerkleTrieLoader, final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader,
final CachedWorldStorageManager cachedWorldStorageManager, final DiffBasedCachedWorldStorageManager cachedWorldStorageManager,
final TrieLogManager trieLogManager, final TrieLogManager trieLogManager,
final BonsaiPreImageProxy preImageProxy, final BonsaiPreImageProxy preImageProxy,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
super( super(
worldStateKeyValueStorage, worldStateKeyValueStorage,
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
cachedWorldStorageManager, cachedWorldStorageManager,
trieLogManager, trieLogManager,
evmConfiguration); evmConfiguration);
@ -72,21 +74,21 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
new BonsaiReferenceTestUpdateAccumulator( new BonsaiReferenceTestUpdateAccumulator(
this, this,
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadAccount( bonsaiCachedMerkleTrieLoader.preLoadAccount(
getWorldStateStorage(), worldStateRootHash, addr), getWorldStateStorage(), worldStateRootHash, addr),
(addr, value) -> (addr, value) ->
cachedMerkleTrieLoader.preLoadStorageSlot(getWorldStateStorage(), addr, value), bonsaiCachedMerkleTrieLoader.preLoadStorageSlot(
getWorldStateStorage(), addr, value),
preImageProxy, preImageProxy,
evmConfiguration)); evmConfiguration));
} }
@Override @Override
public ReferenceTestWorldState copy() { public ReferenceTestWorldState copy() {
var layerCopy = var layerCopy = new BonsaiReferenceTestWorldStateStorage(getWorldStateStorage(), preImageProxy);
new BonsaiReferenceTestWorldStateStorage(worldStateKeyValueStorage, preImageProxy);
return new BonsaiReferenceTestWorldState( return new BonsaiReferenceTestWorldState(
layerCopy, layerCopy,
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
cachedWorldStorageManager, cachedWorldStorageManager,
trieLogManager, trieLogManager,
preImageProxy, preImageProxy,
@ -187,8 +189,9 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
private BonsaiWorldState createBonsaiWorldState(final boolean isFrozen) { private BonsaiWorldState createBonsaiWorldState(final boolean isFrozen) {
BonsaiWorldState bonsaiWorldState = BonsaiWorldState bonsaiWorldState =
new BonsaiWorldState( new BonsaiWorldState(
new BonsaiWorldStateLayerStorage(worldStateKeyValueStorage), new BonsaiWorldStateLayerStorage(
cachedMerkleTrieLoader, (BonsaiWorldStateKeyValueStorage) worldStateKeyValueStorage),
bonsaiCachedMerkleTrieLoader,
cachedWorldStorageManager, cachedWorldStorageManager,
trieLogManager, trieLogManager,
evmConfiguration); evmConfiguration);
@ -209,8 +212,11 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
final Map<String, ReferenceTestWorldState.AccountMock> accounts, final Map<String, ReferenceTestWorldState.AccountMock> accounts,
final EvmConfiguration evmConfiguration) { final EvmConfiguration evmConfiguration) {
final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem(); final ObservableMetricsSystem metricsSystem = new NoOpMetricsSystem();
final CachedMerkleTrieLoader cachedMerkleTrieLoader = new CachedMerkleTrieLoader(metricsSystem);
final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader =
new BonsaiCachedMerkleTrieLoader(metricsSystem);
final TrieLogManager trieLogManager = new ReferenceTestsInMemoryTrieLogManager(); final TrieLogManager trieLogManager = new ReferenceTestsInMemoryTrieLogManager();
final BonsaiPreImageProxy preImageProxy = final BonsaiPreImageProxy preImageProxy =
new BonsaiPreImageProxy.BonsaiReferenceTestPreImageProxy(); new BonsaiPreImageProxy.BonsaiReferenceTestPreImageProxy();
@ -223,13 +229,13 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage = final BonsaiReferenceTestWorldStateStorage worldStateKeyValueStorage =
new BonsaiReferenceTestWorldStateStorage(bonsaiWorldStateKeyValueStorage, preImageProxy); new BonsaiReferenceTestWorldStateStorage(bonsaiWorldStateKeyValueStorage, preImageProxy);
final NoOpCachedWorldStorageManager noOpCachedWorldStorageManager = final NoOpBonsaiCachedWorldStorageManager noOpCachedWorldStorageManager =
new NoOpCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage); new NoOpBonsaiCachedWorldStorageManager(bonsaiWorldStateKeyValueStorage);
final BonsaiReferenceTestWorldState worldState = final BonsaiReferenceTestWorldState worldState =
new BonsaiReferenceTestWorldState( new BonsaiReferenceTestWorldState(
worldStateKeyValueStorage, worldStateKeyValueStorage,
cachedMerkleTrieLoader, bonsaiCachedMerkleTrieLoader,
noOpCachedWorldStorageManager, noOpCachedWorldStorageManager,
trieLogManager, trieLogManager,
preImageProxy, preImageProxy,
@ -260,10 +266,10 @@ public class BonsaiReferenceTestWorldState extends BonsaiWorldState
@Override @Override
public synchronized void saveTrieLog( public synchronized void saveTrieLog(
final BonsaiWorldStateUpdateAccumulator localUpdater, final DiffBasedWorldStateUpdateAccumulator<?> localUpdater,
final Hash forWorldStateRootHash, final Hash forWorldStateRootHash,
final BlockHeader forBlockHeader, final BlockHeader forBlockHeader,
final BonsaiWorldState forWorldState) { final DiffBasedWorldState forWorldState) {
// notify trie log added observers, synchronously // notify trie log added observers, synchronously
TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader); TrieLog trieLog = trieLogFactory.create(localUpdater, forBlockHeader);
trieLogCache.put(forBlockHeader.getHash(), trieLogFactory.serialize(trieLog)); trieLogCache.put(forBlockHeader.getHash(), trieLogFactory.serialize(trieLog));

@ -16,11 +16,11 @@ package org.hyperledger.besu.ethereum.referencetests;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.trie.bonsai.BonsaiAccount; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiPreImageProxy; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiPreImageProxy;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateLayerStorage; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateLayerStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldView; import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldView;
import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.account.AccountStorageEntry;
import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldState;
@ -64,7 +64,7 @@ public class BonsaiReferenceTestWorldStateStorage extends BonsaiWorldStateLayerS
} }
public Stream<WorldState.StreamableAccount> streamAccounts( public Stream<WorldState.StreamableAccount> streamAccounts(
final BonsaiWorldView context, final Bytes32 startKeyHash, final int limit) { final DiffBasedWorldView context, final Bytes32 startKeyHash, final int limit) {
return streamFlatAccounts(startKeyHash, UInt256.MAX_VALUE, limit) return streamFlatAccounts(startKeyHash, UInt256.MAX_VALUE, limit)
.entrySet() .entrySet()
// map back to addresses using preImage provider: // map back to addresses using preImage provider:

@ -13,4 +13,4 @@ org.gradle.jvmargs=-Xmx4g \
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \ --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
--add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-opens jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
# Could be moved to sonar properties after https://sonarsource.atlassian.net/browse/SONARGRADL-134 # Could be moved to sonar properties after https://sonarsource.atlassian.net/browse/SONARGRADL-134
systemProp.sonar.gradle.skipCompile=true systemProp.sonar.gradle.skipCompile=true
Loading…
Cancel
Save