Fix storage range issue during snapsync (#7624)

Signed-off-by: Karim Taam <karim.t2am@gmail.com>
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
pull/7713/head
Karim Taam 2 months ago committed by GitHub
parent 49bf37cc31
commit 9310e1031d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java
  2. 105
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/AccountHealingTrackingTest.java

@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync.request;
import static org.hyperledger.besu.ethereum.eth.sync.snapsync.RequestType.STORAGE_RANGE;
import static org.hyperledger.besu.ethereum.eth.sync.snapsync.StackTrie.FlatDatabaseUpdater.noop;
import static org.hyperledger.besu.ethereum.trie.RangeManager.MAX_RANGE;
import static org.hyperledger.besu.ethereum.trie.RangeManager.MIN_RANGE;
import static org.hyperledger.besu.ethereum.trie.RangeManager.findNewBeginElementInRange;
import static org.hyperledger.besu.ethereum.trie.RangeManager.getRangeCount;
@ -192,11 +191,12 @@ public class StorageRangeDataRequest extends SnapDataRequest {
getRootHash(), accountHash, storageRoot, key, value);
childRequests.add(storageRangeDataRequest);
});
if (startKeyHash.equals(MIN_RANGE) && endKeyHash.equals(MAX_RANGE)) {
});
if (startKeyHash.equals(MIN_RANGE) && !taskElement.proofs().isEmpty()) {
// need to heal this account storage
downloadState.addAccountToHealingList(CompactEncoding.bytesToPath(accountHash));
}
});
return childRequests.stream();
}

@ -64,9 +64,7 @@ public class AccountHealingTrackingTest {
DataStorageConfiguration.DEFAULT_BONSAI_CONFIG);
private WorldStateStorageCoordinator worldStateStorageCoordinator;
private WorldStateProofProvider worldStateProofProvider;
private MerkleTrie<Bytes, Bytes> accountStateTrie;
@Mock SnapWorldDownloadState snapWorldDownloadState;
@ -82,9 +80,7 @@ public class AccountHealingTrackingTest {
}
@Test
void avoidMarkingAccountWhenStorageProofValid() {
// generate valid proof
void shouldMarkAccountForHealingWhenStorageProofIsReceived() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -108,7 +104,7 @@ public class AccountHealingTrackingTest {
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
// generate the proof
final List<Bytes> proofs =
worldStateProofProvider.getStorageProofRelatedNodes(
Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO);
@ -127,11 +123,53 @@ public class AccountHealingTrackingTest {
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs));
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void shouldNotMarkAccountForHealingWhenAllStorageIsReceivedWithoutProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
new StoredNodeFactory<>(
(location, hash) ->
worldStateKeyValueStorage.getAccountStorageTrieNode(
accountHash, location, hash),
Function.identity(),
Function.identity()),
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 10, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
storageTrie.entriesFrom(
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
final StorageRangeDataRequest storageRangeDataRequest =
SnapDataRequest.createStorageRangeDataRequest(
Hash.wrap(accountStateTrie.getRootHash()),
accountHash,
storageTrie.getRootHash(),
Hash.ZERO,
MAX_RANGE);
storageRangeDataRequest.addResponse(
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>());
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
}
@Test
void markAccountOnInvalidStorageProof() {
void shouldMarkAccountForHealingOnInvalidStorageProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -157,8 +195,7 @@ public class AccountHealingTrackingTest {
}
@Test
void markAccountOnPartialStorageRange() {
// generate valid proof
void shouldMarkAccountForHealingOnInvalidStorageWithoutProof() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -174,11 +211,46 @@ public class AccountHealingTrackingTest {
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 1, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
storageTrie.entriesFrom(
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
final StorageRangeDataRequest storageRangeDataRequest =
SnapDataRequest.createStorageRangeDataRequest(
Hash.wrap(accountStateTrie.getRootHash()),
accountHash,
storageTrie.getRootHash(),
Hash.ZERO,
MAX_RANGE,
1,
Integer.MAX_VALUE); // limit to 1 in order to have a partial range
MAX_RANGE);
storageRangeDataRequest.addResponse(
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>());
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void shouldMarkAccountForHealingOnPartialStorageRange() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
final StoredMerklePatriciaTrie<Bytes, Bytes> storageTrie =
new StoredMerklePatriciaTrie<>(
new StoredNodeFactory<>(
(location, hash) ->
worldStateKeyValueStorage.getAccountStorageTrieNode(
accountHash, location, hash),
Function.identity(),
Function.identity()),
stateTrieAccountValue.getStorageRoot());
final RangeStorageEntriesCollector collector =
RangeStorageEntriesCollector.createCollector(Hash.ZERO, MAX_RANGE, 1, Integer.MAX_VALUE);
final TrieIterator<Bytes> visitor = RangeStorageEntriesCollector.createVisitor(collector);
final TreeMap<Bytes32, Bytes> slots =
(TreeMap<Bytes32, Bytes>)
@ -186,7 +258,7 @@ public class AccountHealingTrackingTest {
root ->
RangeStorageEntriesCollector.collectEntries(
collector, visitor, root, Hash.ZERO));
// generate the proof
final List<Bytes> proofs =
worldStateProofProvider.getStorageProofRelatedNodes(
Hash.wrap(storageTrie.getRootHash()), accountHash, Hash.ZERO);
@ -205,14 +277,14 @@ public class AccountHealingTrackingTest {
snapWorldDownloadState, worldStateProofProvider, slots, new ArrayDeque<>(proofs));
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
// should mark during the getchild request
storageRangeDataRequest.getChildRequests(
snapWorldDownloadState, worldStateStorageCoordinator, null);
verify(snapWorldDownloadState).addAccountToHealingList(any(Bytes.class));
}
@Test
void avoidMarkingAccountOnValidStorageTrieNodeDetection() {
void shouldNotMarkAccountForHealingOnValidStorageTrieNodeDetection() {
final Hash accountHash = Hash.hash(accounts.get(0));
final StateTrieAccountValue stateTrieAccountValue =
StateTrieAccountValue.readFrom(RLP.input(accountStateTrie.get(accountHash).orElseThrow()));
@ -223,6 +295,7 @@ public class AccountHealingTrackingTest {
Hash.wrap(accountStateTrie.getRootHash()),
Bytes.EMPTY);
storageTrieNodeHealingRequest.getExistingData(worldStateStorageCoordinator);
verify(snapWorldDownloadState, never()).addAccountToHealingList(any(Bytes.class));
}
}

Loading…
Cancel
Save