Skip to content

Commit

Permalink
worldstate refactor (hyperledger#6209)
Browse files Browse the repository at this point in the history
* worldstate storage refactor

Signed-off-by: Karim TAAM <[email protected]>
Signed-off-by: Gabriel Fukushima <[email protected]>
Co-authored-by: Gabriel Fukushima <[email protected]>
  • Loading branch information
2 people authored and matthew1001 committed Jun 7, 2024
1 parent 84d2431 commit 974b9c9
Show file tree
Hide file tree
Showing 105 changed files with 1,800 additions and 1,244 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.eth.manager.EthScheduler;
import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;

import java.io.File;
Expand Down Expand Up @@ -81,15 +81,19 @@ public void run() {

final BesuController besuController = createBesuController();
final MutableBlockchain blockchain = besuController.getProtocolContext().getBlockchain();
final WorldStateStorage worldStateStorage =
final ForestWorldStateKeyValueStorage forestWorldStateKeyValueStorage =
((ForestWorldStateArchive) besuController.getProtocolContext().getWorldStateArchive())
.getWorldStateStorage();
final EthScheduler scheduler = new EthScheduler(1, 1, 1, 1, new NoOpMetricsSystem());
try {
final long targetBlock = Math.min(blockchain.getChainHeadBlockNumber(), this.block);
final StateBackupService backup =
new StateBackupService(
BesuInfo.version(), blockchain, backupDir.toPath(), scheduler, worldStateStorage);
BesuInfo.version(),
blockchain,
backupDir.toPath(),
scheduler,
forestWorldStateKeyValueStorage);
final BackupStatus status = backup.requestBackup(targetBlock, compress, Optional.empty());

final double refValue = Math.pow(2, 256) / 100.0d;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
import org.hyperledger.besu.ethereum.trie.PersistVisitor;
import org.hyperledger.besu.ethereum.trie.RestoreVisitor;
import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.util.io.RollingFileReader;

import java.io.IOException;
Expand Down Expand Up @@ -83,7 +83,7 @@ public class RestoreState implements Runnable {
private long trieNodeCount;
private boolean compressed;
private BesuController besuController;
private WorldStateStorage.Updater updater;
private ForestWorldStateKeyValueStorage.Updater updater;

private Path accountFileName(final int fileNumber, final boolean compressed) {
return StateBackupService.accountFileName(backupDir, targetBlock, fileNumber, compressed);
Expand Down Expand Up @@ -249,10 +249,10 @@ private void newWorldStateUpdater() {
if (updater != null) {
updater.commit();
}
final WorldStateStorage worldStateStorage =
final ForestWorldStateKeyValueStorage worldStateKeyValueStorage =
((ForestWorldStateArchive) besuController.getProtocolContext().getWorldStateArchive())
.getWorldStateStorage();
updater = worldStateStorage.updater();
updater = worldStateKeyValueStorage.updater();
}

private void maybeCommitUpdater() {
Expand All @@ -263,20 +263,20 @@ private void maybeCommitUpdater() {

private void updateCode(final Bytes code) {
maybeCommitUpdater();
updater.putCode(null, code);
updater.putCode(code);
}

private void updateAccountState(final Bytes32 key, final Bytes value) {
maybeCommitUpdater();
// restore by path not supported
updater.putAccountStateTrieNode(null, key, value);
updater.putAccountStateTrieNode(key, value);
trieNodeCount++;
}

private void updateAccountStorage(final Bytes32 key, final Bytes value) {
maybeCommitUpdater();
// restore by path not supported
updater.putAccountStorageTrieNode(null, null, key, value);
updater.putAccountStorageTrieNode(key, value);
trieNodeCount++;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.services.MetricsSystem;
Expand Down Expand Up @@ -559,8 +560,8 @@ public BesuController build() {

final VariablesStorage variablesStorage = storageProvider.createVariablesStorage();

final WorldStateStorage worldStateStorage =
storageProvider.createWorldStateStorage(dataStorageConfiguration);
final WorldStateStorageCoordinator worldStateStorageCoordinator =
storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration);

final BlockchainStorage blockchainStorage =
storageProvider.createBlockchainStorage(protocolSchedule, variablesStorage);
Expand All @@ -580,7 +581,7 @@ public BesuController build() {
.orElseGet(() -> new CachedMerkleTrieLoader(metricsSystem));

final WorldStateArchive worldStateArchive =
createWorldStateArchive(worldStateStorage, blockchain, cachedMerkleTrieLoader);
createWorldStateArchive(worldStateStorageCoordinator, blockchain, cachedMerkleTrieLoader);

if (blockchain.getChainHeadBlockNumber() < 1) {
genesisState.writeStateTo(worldStateArchive.getMutable());
Expand Down Expand Up @@ -707,7 +708,7 @@ public BesuController build() {
final Synchronizer synchronizer =
createSynchronizer(
protocolSchedule,
worldStateStorage,
worldStateStorageCoordinator,
protocolContext,
maybePruner,
ethContext,
Expand Down Expand Up @@ -739,8 +740,10 @@ public BesuController build() {
&& DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) {
final TrieLogManager trieLogManager =
((BonsaiWorldStateProvider) worldStateArchive).getTrieLogManager();
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
final TrieLogPruner trieLogPruner =
createTrieLogPruner(worldStateStorage, blockchain, scheduler);
createTrieLogPruner(worldStateKeyValueStorage, blockchain, scheduler);
trieLogManager.subscribe(trieLogPruner);
}

Expand Down Expand Up @@ -773,7 +776,7 @@ public BesuController build() {
}

private TrieLogPruner createTrieLogPruner(
final WorldStateStorage worldStateStorage,
final WorldStateKeyValueStorage worldStateStorage,
final Blockchain blockchain,
final EthScheduler scheduler) {
final GenesisConfigOptions genesisConfigOptions = configOptionsSupplier.get();
Expand All @@ -796,7 +799,7 @@ private TrieLogPruner createTrieLogPruner(
* Create synchronizer synchronizer.
*
* @param protocolSchedule the protocol schedule
* @param worldStateStorage the world state storage
* @param worldStateStorageCoordinator the world state storage
* @param protocolContext the protocol context
* @param maybePruner the maybe pruner
* @param ethContext the eth context
Expand All @@ -807,7 +810,7 @@ private TrieLogPruner createTrieLogPruner(
*/
protected Synchronizer createSynchronizer(
final ProtocolSchedule protocolSchedule,
final WorldStateStorage worldStateStorage,
final WorldStateStorageCoordinator worldStateStorageCoordinator,
final ProtocolContext protocolContext,
final Optional<Pruner> maybePruner,
final EthContext ethContext,
Expand All @@ -819,7 +822,7 @@ protected Synchronizer createSynchronizer(
syncConfig,
protocolSchedule,
protocolContext,
worldStateStorage,
worldStateStorageCoordinator,
ethProtocolManager.getBlockBroadcaster(),
maybePruner,
ethContext,
Expand Down Expand Up @@ -1042,21 +1045,26 @@ private Optional<SnapProtocolManager> createSnapProtocolManager(
}

WorldStateArchive createWorldStateArchive(
final WorldStateStorage worldStateStorage,
final WorldStateStorageCoordinator worldStateStorageCoordinator,
final Blockchain blockchain,
final CachedMerkleTrieLoader cachedMerkleTrieLoader) {
return switch (dataStorageConfiguration.getDataStorageFormat()) {
case BONSAI -> new BonsaiWorldStateProvider(
(BonsaiWorldStateKeyValueStorage) worldStateStorage,
blockchain,
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
cachedMerkleTrieLoader,
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration);
case BONSAI -> {
final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage =
worldStateStorageCoordinator.getStrategy(BonsaiWorldStateKeyValueStorage.class);
yield new BonsaiWorldStateProvider(
worldStateKeyValueStorage,
blockchain,
Optional.of(dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
cachedMerkleTrieLoader,
besuComponent.map(BesuComponent::getBesuPluginContext).orElse(null),
evmConfiguration);
}
case FOREST -> {
final WorldStatePreimageStorage preimageStorage =
storageProvider.createWorldStatePreimageStorage();
yield new ForestWorldStateArchive(worldStateStorage, preimageStorage, evmConfiguration);
yield new ForestWorldStateArchive(
worldStateStorageCoordinator, preimageStorage, evmConfiguration);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.services.permissioning.NodeMessagePermissioningProvider;
Expand Down Expand Up @@ -217,7 +217,7 @@ protected PluginServiceFactory createAdditionalPluginServices(
@Override
protected Synchronizer createSynchronizer(
final ProtocolSchedule protocolSchedule,
final WorldStateStorage worldStateStorage,
final WorldStateStorageCoordinator worldStateStorageCoordinator,
final ProtocolContext protocolContext,
final Optional<Pruner> maybePruner,
final EthContext ethContext,
Expand All @@ -229,7 +229,7 @@ protected Synchronizer createSynchronizer(
(DefaultSynchronizer)
super.createSynchronizer(
protocolSchedule,
worldStateStorage,
worldStateStorageCoordinator,
protocolContext,
maybePruner,
ethContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@
import org.hyperledger.besu.ethereum.trie.bonsai.storage.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
Expand Down Expand Up @@ -89,7 +90,6 @@ public class BesuControllerBuilderTest {
@Mock Clock clock;
@Mock StorageProvider storageProvider;
@Mock GasLimitCalculator gasLimitCalculator;
@Mock WorldStateStorage worldStateStorage;
@Mock WorldStateArchive worldStateArchive;
@Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage;
@Mock WorldStatePreimageStorage worldStatePreimageStorage;
Expand All @@ -105,6 +105,12 @@ public class BesuControllerBuilderTest {

@BeforeEach
public void setup() {

final ForestWorldStateKeyValueStorage worldStateKeyValueStorage =
mock(ForestWorldStateKeyValueStorage.class);
final WorldStateStorageCoordinator worldStateStorageCoordinator =
new WorldStateStorageCoordinator(worldStateKeyValueStorage);

when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString());
when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString());
when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString());
Expand Down Expand Up @@ -132,17 +138,21 @@ public void setup() {

lenient()
.when(
storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG))
.thenReturn(worldStateStorage);
storageProvider.createWorldStateStorageCoordinator(
DataStorageConfiguration.DEFAULT_FOREST_CONFIG))
.thenReturn(worldStateStorageCoordinator);
lenient()
.when(storageProvider.createWorldStatePreimageStorage())
.thenReturn(worldStatePreimageStorage);

lenient().when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true);
lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true);
lenient()
.when(worldStatePreimageStorage.updater())
.thenReturn(mock(WorldStatePreimageStorage.Updater.class));
lenient().when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class));
lenient()
.when(worldStateKeyValueStorage.updater())
.thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class));

besuControllerBuilder = spy(visitWithMockConfigs(new MainnetBesuControllerBuilder()));
}

Expand All @@ -167,18 +177,23 @@ BesuControllerBuilder visitWithMockConfigs(final BesuControllerBuilder builder)

@Test
public void shouldDisablePruningIfBonsaiIsEnabled() {
DataStorageConfiguration dataStorageConfiguration =
ImmutableDataStorageConfiguration.builder()
.dataStorageFormat(DataStorageFormat.BONSAI)
.bonsaiMaxLayersToLoad(DataStorageConfiguration.DEFAULT_BONSAI_MAX_LAYERS_TO_LOAD)
.build();
BonsaiWorldState mockWorldState = mock(BonsaiWorldState.class, Answers.RETURNS_DEEP_STUBS);
doReturn(worldStateArchive)
.when(besuControllerBuilder)
.createWorldStateArchive(
any(WorldStateStorage.class), any(Blockchain.class), any(CachedMerkleTrieLoader.class));
any(WorldStateStorageCoordinator.class),
any(Blockchain.class),
any(CachedMerkleTrieLoader.class));
doReturn(mockWorldState).when(worldStateArchive).getMutable();
when(storageProvider.createWorldStateStorageCoordinator(dataStorageConfiguration))
.thenReturn(new WorldStateStorageCoordinator(bonsaiWorldStateStorage));
besuControllerBuilder.isPruningEnabled(true).dataStorageConfiguration(dataStorageConfiguration);

when(storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG))
.thenReturn(bonsaiWorldStateStorage);
besuControllerBuilder
.isPruningEnabled(true)
.dataStorageConfiguration(DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
besuControllerBuilder.build();

verify(storageProvider, never())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@
import org.hyperledger.besu.ethereum.storage.StorageProvider;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage;
import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage;
import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethereum.worldstate.WorldStatePreimageStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
Expand Down Expand Up @@ -99,7 +100,6 @@ public class MergeBesuControllerBuilderTest {
@Mock Clock clock;
@Mock StorageProvider storageProvider;
@Mock GasLimitCalculator gasLimitCalculator;
@Mock WorldStateStorage worldStateStorage;
@Mock WorldStatePreimageStorage worldStatePreimageStorage;

BigInteger networkId = BigInteger.ONE;
Expand All @@ -113,6 +113,12 @@ public class MergeBesuControllerBuilderTest {

@BeforeEach
public void setup() {

final ForestWorldStateKeyValueStorage worldStateKeyValueStorage =
mock(ForestWorldStateKeyValueStorage.class);
final WorldStateStorageCoordinator worldStateStorageCoordinator =
new WorldStateStorageCoordinator(worldStateKeyValueStorage);

lenient().when(genesisConfigFile.getParentHash()).thenReturn(Hash.ZERO.toHexString());
lenient().when(genesisConfigFile.getDifficulty()).thenReturn(Bytes.of(0).toHexString());
lenient().when(genesisConfigFile.getExtraData()).thenReturn(Bytes.EMPTY.toHexString());
Expand Down Expand Up @@ -146,17 +152,20 @@ public void setup() {

lenient()
.when(
storageProvider.createWorldStateStorage(DataStorageConfiguration.DEFAULT_FOREST_CONFIG))
.thenReturn(worldStateStorage);
storageProvider.createWorldStateStorageCoordinator(
DataStorageConfiguration.DEFAULT_FOREST_CONFIG))
.thenReturn(worldStateStorageCoordinator);
lenient()
.when(storageProvider.createWorldStatePreimageStorage())
.thenReturn(worldStatePreimageStorage);

lenient().when(worldStateStorage.isWorldStateAvailable(any(), any())).thenReturn(true);
lenient().when(worldStateKeyValueStorage.isWorldStateAvailable(any())).thenReturn(true);
lenient()
.when(worldStatePreimageStorage.updater())
.thenReturn(mock(WorldStatePreimageStorage.Updater.class));
lenient().when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class));
lenient()
.when(worldStateKeyValueStorage.updater())
.thenReturn(mock(ForestWorldStateKeyValueStorage.Updater.class));
lenient().when(miningParameters.getTargetGasLimit()).thenReturn(OptionalLong.empty());

besuControllerBuilder = visitWithMockConfigs(new MergeBesuControllerBuilder());
Expand Down
Loading

0 comments on commit 974b9c9

Please sign in to comment.