Skip to content

Commit

Permalink
candidate fix for missing parent worldstate (#4094)
Browse files Browse the repository at this point in the history
* candidate fix for missing parent worldstate
* add rollback if failure
* fix persist trie log issue
* add trielog manager
* fix inmemory issue for bonsai

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>

Co-authored-by: garyschulte <garyschulte@gmail.com>
Co-authored-by: Justin Florentine <justin+github@florentine.us>
  • Loading branch information
3 people authored Jul 18, 2022
1 parent ac3e075 commit 3ce7f0f
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateArchive;
import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.bonsai.TrieLogManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.BlockchainStorage;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
Expand Down Expand Up @@ -602,7 +604,12 @@ private WorldStateArchive createWorldStateArchive(
switch (dataStorageConfiguration.getDataStorageFormat()) {
case BONSAI:
return new BonsaiWorldStateArchive(
storageProvider, blockchain, dataStorageConfiguration.getBonsaiMaxLayersToLoad());
new TrieLogManager(
blockchain,
(BonsaiWorldStateKeyValueStorage) worldStateStorage,
dataStorageConfiguration.getBonsaiMaxLayersToLoad()),
storageProvider,
blockchain);
case FOREST:
default:
final WorldStatePreimageStorage preimageStorage =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStorage;
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration;
Expand All @@ -46,6 +47,7 @@
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.plugin.services.storage.KeyValueStorageTransaction;
import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage;

import java.math.BigInteger;
Expand Down Expand Up @@ -83,6 +85,7 @@ public class BesuControllerBuilderTest {
@Mock StorageProvider storageProvider;
@Mock GasLimitCalculator gasLimitCalculator;
@Mock WorldStateStorage worldStateStorage;
@Mock BonsaiWorldStateKeyValueStorage bonsaiWorldStateStorage;
@Mock WorldStatePreimageStorage worldStatePreimageStorage;

BigInteger networkId = BigInteger.ONE;
Expand Down Expand Up @@ -128,7 +131,11 @@ public void setup() {
when(worldStatePreimageStorage.updater())
.thenReturn(mock(WorldStatePreimageStorage.Updater.class));
when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class));

BonsaiWorldStateKeyValueStorage.Updater bonsaiUpdater =
mock(BonsaiWorldStateKeyValueStorage.Updater.class);
when(bonsaiUpdater.getTrieLogStorageTransaction())
.thenReturn(mock(KeyValueStorageTransaction.class));
when(bonsaiWorldStateStorage.updater()).thenReturn(bonsaiUpdater);
besuControllerBuilder = visitWithMockConfigs(new MainnetBesuControllerBuilder());
}

Expand All @@ -152,6 +159,8 @@ BesuControllerBuilder visitWithMockConfigs(final BesuControllerBuilder builder)

@Test
public void shouldDisablePruningIfBonsaiIsEnabled() {
when(storageProvider.createWorldStateStorage(DataStorageFormat.BONSAI))
.thenReturn(bonsaiWorldStateStorage);
besuControllerBuilder
.isPruningEnabled(true)
.dataStorageConfiguration(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

public class BonsaiInMemoryWorldState extends BonsaiPersistedWorldState {

private boolean isPersisted = false;

public BonsaiInMemoryWorldState(
final BonsaiWorldStateArchive archive,
final BonsaiWorldStateKeyValueStorage worldStateStorage) {
Expand All @@ -29,9 +31,16 @@ public BonsaiInMemoryWorldState(

@Override
public Hash rootHash() {
if (isPersisted) {
return worldStateRootHash;
}
return rootHash(updater.copy());
}

public Hash rootHash(final BonsaiWorldStateUpdater localUpdater) {
final BonsaiWorldStateKeyValueStorage.Updater updater = worldStateStorage.updater();
try {
final Hash calculatedRootHash = calculateRootHash(updater);
final Hash calculatedRootHash = calculateRootHash(updater, localUpdater);
return Hash.wrap(calculatedRootHash);
} finally {
updater.rollback();
Expand All @@ -41,13 +50,12 @@ public Hash rootHash() {
@Override
public void persist(final BlockHeader blockHeader) {
final BonsaiWorldStateUpdater localUpdater = updater.copy();
try {
final Hash newWorldStateRootHash = rootHash();
prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash);
worldStateBlockHash = blockHeader.getHash();
worldStateRootHash = newWorldStateRootHash;
} finally {
localUpdater.reset();
}
final Hash newWorldStateRootHash = rootHash(localUpdater);
archive
.getTrieLogManager()
.saveTrieLog(archive, localUpdater, newWorldStateRootHash, blockHeader);
worldStateRootHash = newWorldStateRootHash;
worldStateBlockHash = blockHeader.getBlockHash();
isPersisted = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.trie.StoredMerklePatriciaTrie;
import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage;
import org.hyperledger.besu.evm.account.Account;
Expand Down Expand Up @@ -100,10 +99,6 @@ public BonsaiWorldStateKeyValueStorage getWorldStateStorage() {
return worldStateStorage;
}

protected Hash calculateRootHash(final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) {
return calculateRootHash(stateUpdater, updater.copy());
}

protected Hash calculateRootHash(
final BonsaiWorldStateKeyValueStorage.Updater stateUpdater,
final BonsaiWorldStateUpdater worldStateUpdater) {
Expand Down Expand Up @@ -252,14 +247,16 @@ public void persist(final BlockHeader blockHeader) {
// then persist the TrieLog for that transition.
// If specified but not a direct descendant simply store the new block hash.
if (blockHeader != null) {
// do not overwrite a trielog layer that already exists in the database.
// if it's only in memory we need to save it
// for example, like that in case of reorg we don't replace a trielog layer
if (worldStateStorage.getTrieLog(blockHeader.getHash()).isEmpty()) {
final TrieLogLayer trieLog =
prepareTrieLog(blockHeader, localUpdater, newWorldStateRootHash);
persistTrieLog(blockHeader, newWorldStateRootHash, trieLog, stateUpdater);
if (!newWorldStateRootHash.equals(blockHeader.getStateRoot())) {
throw new RuntimeException(
"World State Root does not match expected value, header "
+ blockHeader.getStateRoot().toHexString()
+ " calculated "
+ newWorldStateRootHash.toHexString());
}
archive
.getTrieLogManager()
.saveTrieLog(archive, localUpdater, newWorldStateRootHash, blockHeader);
stateUpdater
.getTrieBranchStorageTransaction()
.put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe());
Expand All @@ -283,46 +280,6 @@ public void persist(final BlockHeader blockHeader) {
updater.reset();
}
}
if (blockHeader != null) {
archive.scrubLayeredCache(blockHeader.getNumber());
}
}

protected TrieLogLayer prepareTrieLog(
final BlockHeader blockHeader,
final BonsaiWorldStateUpdater localUpdater,
final Hash currentWorldStateRootHash) {

if (!currentWorldStateRootHash.equals(blockHeader.getStateRoot())) {
throw new RuntimeException(
"World State Root does not match expected value, header "
+ blockHeader.getStateRoot().toHexString()
+ " calculated "
+ currentWorldStateRootHash.toHexString());
}

debugLambda(LOG, "Adding layered world state for {}", blockHeader::toLogString);
final TrieLogLayer trieLog = localUpdater.generateTrieLog(blockHeader.getBlockHash());
trieLog.freeze();
archive.addLayeredWorldState(this, blockHeader, currentWorldStateRootHash, trieLog);
return trieLog;
}

private void persistTrieLog(
final BlockHeader blockHeader,
final Hash worldStateRootHash,
final TrieLogLayer trieLog,
final BonsaiWorldStateKeyValueStorage.Updater stateUpdater) {
debugLambda(
LOG,
"Persisting trie log for block hash {} and world state root {}",
blockHeader::toLogString,
worldStateRootHash::toHexString);
final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput();
trieLog.writeTo(rlpLog);
stateUpdater
.getTrieLogStorageTransaction()
.put(blockHeader.getHash().toArrayUnsafe(), rlpLog.encoded().toArrayUnsafe());
}

@Override
Expand Down
Loading

0 comments on commit 3ce7f0f

Please sign in to comment.