use of org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater in project besu by hyperledger.
the class FastWorldStateDownloaderTest method doesNotRequestKnownStorageTrieNodesFromNetwork.
@Test
public void doesNotRequestKnownStorageTrieNodesFromNetwork() {
// Setup "remote" state
final WorldStateStorage remoteStorage = new WorldStateKeyValueStorage(new InMemoryKeyValueStorage());
final WorldStateArchive remoteWorldStateArchive = new DefaultWorldStateArchive(remoteStorage, createPreimageStorage());
final MutableWorldState remoteWorldState = remoteWorldStateArchive.getMutable();
// Generate accounts and save corresponding state root
final List<Account> accounts = dataGen.createRandomContractAccountsWithNonEmptyStorage(remoteWorldState, 20);
final Hash stateRoot = remoteWorldState.rootHash();
final BlockHeader header = dataGen.block(BlockOptions.create().setStateRoot(stateRoot).setBlockNumber(10)).getHeader();
// Create some peers
final List<RespondingEthPeer> peers = Stream.generate(() -> EthProtocolManagerTestUtil.createPeer(ethProtocolManager, header.getNumber())).limit(5).collect(Collectors.toList());
final InMemoryTasksPriorityQueues<NodeDataRequest> taskCollection = new InMemoryTasksPriorityQueues<>();
final WorldStateStorage localStorage = new WorldStateKeyValueStorage(new InMemoryKeyValueStorage());
// Seed local storage with some trie node values
final List<Bytes32> storageRootHashes = new StoredMerklePatriciaTrie<>(remoteStorage::getNodeData, remoteWorldState.rootHash(), Function.identity(), Function.identity()).entriesFrom(Bytes32.ZERO, 5).values().stream().map(RLP::input).map(StateTrieAccountValue::readFrom).map(StateTrieAccountValue::getStorageRoot).collect(Collectors.toList());
final Map<Bytes32, Bytes> allTrieNodes = new HashMap<>();
final Set<Bytes32> knownNodes = new HashSet<>();
final Set<Bytes32> unknownNodes = new HashSet<>();
for (final Bytes32 storageRootHash : storageRootHashes) {
allTrieNodes.putAll(collectTrieNodesToBeRequestedAfterRoot(remoteStorage, storageRootHash, 5));
}
// Sanity check
assertThat(allTrieNodes.size()).isGreaterThan(0);
final Updater localStorageUpdater = localStorage.updater();
boolean storeNode = true;
for (final Map.Entry<Bytes32, Bytes> entry : allTrieNodes.entrySet()) {
final Bytes32 hash = entry.getKey();
final Bytes data = entry.getValue();
if (storeNode) {
localStorageUpdater.putAccountStorageTrieNode(null, null, hash, data);
knownNodes.add(hash);
} else {
unknownNodes.add(hash);
}
storeNode = !storeNode;
}
localStorageUpdater.commit();
final WorldStateDownloader downloader = createDownloader(ethProtocolManager.ethContext(), localStorage, taskCollection);
final FastSyncState fastSyncState = new FastSyncState(header);
final CompletableFuture<Void> result = downloader.run(null, fastSyncState);
// Respond to node data requests
final List<MessageData> sentMessages = new ArrayList<>();
final RespondingEthPeer.Responder blockChainResponder = RespondingEthPeer.blockchainResponder(mock(Blockchain.class), remoteWorldStateArchive, mock(TransactionPool.class));
final RespondingEthPeer.Responder responder = RespondingEthPeer.wrapResponderWithCollector(blockChainResponder, sentMessages);
respondUntilDone(peers, responder, result);
// World state should be available by the time the result is complete
assertThat(localStorage.isWorldStateAvailable(stateRoot, header.getHash())).isTrue();
// Check that unknown trie nodes were requested
final List<Bytes32> requestedHashes = sentMessages.stream().filter(m -> m.getCode() == EthPV63.GET_NODE_DATA).map(GetNodeDataMessage::readFrom).flatMap(m -> StreamSupport.stream(m.hashes().spliterator(), true)).collect(Collectors.toList());
assertThat(requestedHashes.size()).isGreaterThan(0);
assertThat(requestedHashes).containsAll(unknownNodes);
assertThat(requestedHashes).doesNotContainAnyElementsOf(knownNodes);
// Check that all expected account data was downloaded
final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertThat(result).isDone();
assertAccountsMatch(localWorldState, accounts);
}
use of org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater in project besu by hyperledger.
the class StorageRangeDataRequest method doPersist.
@Override
protected int doPersist(final WorldStateStorage worldStateStorage, final Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncState snapSyncState) {
// search incomplete nodes in the range
final AtomicInteger nbNodesSaved = new AtomicInteger();
final AtomicReference<Updater> updaterTmp = new AtomicReference<>(worldStateStorage.updater());
final NodeUpdater nodeUpdater = (location, hash, value) -> {
updaterTmp.get().putAccountStorageTrieNode(accountHash, location, hash, value);
if (nbNodesSaved.getAndIncrement() % 1000 == 0) {
updaterTmp.get().commit();
updaterTmp.set(worldStateStorage.updater());
}
};
stackTrie.commit(nodeUpdater);
updaterTmp.get().commit();
downloadState.getMetricsManager().notifySlotsDownloaded(stackTrie.getElementsCount().get());
return nbNodesSaved.get();
}
use of org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater in project besu by hyperledger.
the class FastWorldDownloadState method checkCompletion.
@Override
public synchronized boolean checkCompletion(final BlockHeader header) {
if (!internalFuture.isDone() && pendingRequests.allTasksCompleted()) {
if (rootNodeData == null) {
enqueueRequest(NodeDataRequest.createAccountDataRequest(header.getStateRoot(), Optional.of(Bytes.EMPTY)));
return false;
}
final Updater updater = worldStateStorage.updater();
updater.saveWorldState(header.getHash(), header.getStateRoot(), rootNodeData);
updater.commit();
internalFuture.complete(null);
// THere are no more inputs to process so make sure we wake up any threads waiting to dequeue
// so they can give up waiting.
notifyAll();
LOG.info("Finished downloading world state from peers");
return true;
} else {
return false;
}
}
use of org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater in project besu by hyperledger.
the class AccountRangeDataRequest method doPersist.
@Override
protected int doPersist(final WorldStateStorage worldStateStorage, final Updater updater, final SnapWorldDownloadState downloadState, final SnapSyncState snapSyncState) {
if (startStorageRange.isPresent() && endStorageRange.isPresent()) {
// rootHash
return 0;
}
// search incomplete nodes in the range
final AtomicInteger nbNodesSaved = new AtomicInteger();
final NodeUpdater nodeUpdater = (location, hash, value) -> {
updater.putAccountStateTrieNode(location, hash, value);
nbNodesSaved.getAndIncrement();
};
stackTrie.commit(nodeUpdater);
downloadState.getMetricsManager().notifyAccountsDownloaded(stackTrie.getElementsCount().get());
return nbNodesSaved.get();
}
use of org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater in project besu by hyperledger.
the class PersistDataStep method persist.
public List<Task<NodeDataRequest>> persist(final List<Task<NodeDataRequest>> tasks, final BlockHeader blockHeader, final WorldDownloadState<NodeDataRequest> downloadState) {
final Updater updater = worldStateStorage.updater();
tasks.stream().map(task -> {
enqueueChildren(task, downloadState);
return task;
}).map(Task::getData).filter(request -> request.getData() != null).forEach(request -> {
if (isRootState(blockHeader, request)) {
downloadState.setRootNodeData(request.getData());
} else {
request.persist(updater);
}
});
updater.commit();
return tasks;
}
Aggregations