fix parent world state is not available issue on bonsai (#4069)

Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
pull/4072/head
matkt 2 years ago committed by GitHub
parent 4d8ef07d67
commit 49e4fd8602
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.md
  2. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/bonsai/BonsaiPersistedWorldState.java
  3. 49
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiWorldStateArchiveTest.java

@ -4,6 +4,9 @@
### Additions and Improvements
### Bug Fixes
- Fixed a trie log layer issue on bonsai during reorg [#4069](https://github.com/hyperledger/besu/pull/4069)
## 22.7.0-RC1
### Additions and Improvements
@ -11,7 +14,6 @@
- When on PoS the head can be only be updated by ForkchoiceUpdate [#3994](https://github.com/hyperledger/besu/pull/3994)
- Version information available in metrics [#3997](https://github.com/hyperledger/besu/pull/3997)
- Add TTD and DNS to Sepolia config [#4024](https://github.com/hyperledger/besu/pull/4024)
- Add terminal block hash and number to Ropsten genesis file [#4026](https://github.com/hyperledger/besu/pull/4026)
- Return `type` with value `0x0` when serializing legacy transactions [#4027](https://github.com/hyperledger/besu/pull/4027)
- Ignore `ForkchoiceUpdate` if `newHead` is an ancestor of the chain head [#4055](https://github.com/hyperledger/besu/pull/4055)

@ -252,9 +252,17 @@ public class BonsaiPersistedWorldState implements MutableWorldState, BonsaiWorld
// 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);
}
stateUpdater
.getTrieBranchStorageTransaction()
.put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe());
worldStateBlockHash = blockHeader.getHash();
} else {
stateUpdater.getTrieBranchStorageTransaction().remove(WORLD_BLOCK_HASH_KEY);
@ -310,9 +318,6 @@ public class BonsaiPersistedWorldState implements MutableWorldState, BonsaiWorld
"Persisting trie log for block hash {} and world state root {}",
blockHeader::toLogString,
worldStateRootHash::toHexString);
stateUpdater
.getTrieBranchStorageTransaction()
.put(WORLD_BLOCK_HASH_KEY, blockHeader.getHash().toArrayUnsafe());
final BytesValueRLPOutput rlpLog = new BytesValueRLPOutput();
trieLog.writeTo(rlpLog);
stateUpdater

@ -21,6 +21,7 @@ import static org.hyperledger.besu.ethereum.bonsai.BonsaiWorldStateKeyValueStora
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -200,4 +201,52 @@ public class BonsaiWorldStateArchiveTest {
verify(updater, times(1)).rollBack(any());
verify(updater, times(1)).rollForward(any());
}
@SuppressWarnings({"unchecked"})
@Test
public void testGetMutableWithRollbackNotOverrideTrieLogLayer() {
final KeyValueStorageTransaction keyValueStorageTransaction =
mock(KeyValueStorageTransaction.class);
when(keyValueStorage.startTransaction()).thenReturn(keyValueStorageTransaction);
final BlockHeader genesis = blockBuilder.number(0).buildHeader();
final BlockHeader blockHeaderChainA =
blockBuilder.number(1).timestamp(1).parentHash(genesis.getHash()).buildHeader();
final BlockHeader blockHeaderChainB =
blockBuilder.number(1).timestamp(2).parentHash(genesis.getHash()).buildHeader();
final Map<Bytes32, BonsaiLayeredWorldState> layeredWorldStatesByHash = mock(HashMap.class);
when(layeredWorldStatesByHash.containsKey(any(Bytes32.class))).thenReturn(true);
when(layeredWorldStatesByHash.get(eq(blockHeaderChainA.getHash())))
.thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS));
when(layeredWorldStatesByHash.get(eq(blockHeaderChainB.getHash())))
.thenReturn(mock(BonsaiLayeredWorldState.class, Answers.RETURNS_MOCKS));
bonsaiWorldStateArchive =
spy(new BonsaiWorldStateArchive(storageProvider, blockchain, 12, layeredWorldStatesByHash));
var updater = spy(bonsaiWorldStateArchive.getUpdater());
when(bonsaiWorldStateArchive.getUpdater()).thenReturn(updater);
// initial persisted state hash key
when(blockchain.getBlockHeader(eq(Hash.ZERO))).thenReturn(Optional.of(blockHeaderChainA));
// fake trie log layer
final BytesValueRLPOutput rlpLogBlockB = new BytesValueRLPOutput();
final TrieLogLayer trieLogLayerBlockB = new TrieLogLayer();
trieLogLayerBlockB.setBlockHash(blockHeaderChainB.getHash());
trieLogLayerBlockB.writeTo(rlpLogBlockB);
when(keyValueStorage.get(blockHeaderChainB.getHash().toArrayUnsafe()))
.thenReturn(Optional.of(rlpLogBlockB.encoded().toArrayUnsafe()));
when(blockchain.getBlockHeader(eq(blockHeaderChainB.getHash())))
.thenReturn(Optional.of(blockHeaderChainB));
when(blockchain.getBlockHeader(eq(genesis.getHash()))).thenReturn(Optional.of(genesis));
assertThat(bonsaiWorldStateArchive.getMutable(null, blockHeaderChainB.getHash()))
.containsInstanceOf(BonsaiPersistedWorldState.class);
// verify is not persisting if already present
verify(keyValueStorageTransaction, never())
.put(eq(blockHeaderChainA.getHash().toArrayUnsafe()), any());
verify(keyValueStorageTransaction, never())
.put(eq(blockHeaderChainB.getHash().toArrayUnsafe()), any());
}
}

Loading…
Cancel
Save