use of org.hyperledger.besu.ethereum.trie.Node in project besu by hyperledger.
the class FastWorldStateDownloaderTest method resumesFromNonEmptyQueue.
@Test
public void resumesFromNonEmptyQueue() {
// 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
List<Account> accounts = dataGen.createRandomAccounts(remoteWorldState, 10);
final Hash stateRoot = remoteWorldState.rootHash();
// Sanity check
assertThat(stateRoot).isNotEqualTo(EMPTY_TRIE_ROOT);
final BlockHeader header = dataGen.block(BlockOptions.create().setStateRoot(stateRoot).setBlockNumber(10)).getHeader();
// Add some nodes to the taskCollection
final InMemoryTasksPriorityQueues<NodeDataRequest> taskCollection = spy(new InMemoryTasksPriorityQueues<>());
List<Bytes32> queuedHashes = getFirstSetOfChildNodeRequests(remoteStorage, stateRoot);
// Sanity check
assertThat(queuedHashes.size()).isGreaterThan(0);
for (Bytes32 bytes32 : queuedHashes) {
taskCollection.add(new AccountTrieNodeDataRequest(Hash.wrap(bytes32), Optional.empty()));
}
// Sanity check
for (final Bytes32 bytes32 : queuedHashes) {
final Hash hash = Hash.wrap(bytes32);
verify(taskCollection, times(1)).add(argThat((r) -> r.getHash().equals(hash)));
}
final WorldStateStorage localStorage = new WorldStateKeyValueStorage(new InMemoryKeyValueStorage());
final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder().worldStateMaxRequestsWithoutProgress(10).build();
final WorldStateDownloader downloader = createDownloader(syncConfig, ethProtocolManager.ethContext(), localStorage, taskCollection);
// Create a peer that can respond
final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, header.getNumber());
// Respond to node data requests
final List<MessageData> sentMessages = new ArrayList<>();
final RespondingEthPeer.Responder blockChainResponder = RespondingEthPeer.blockchainResponder(mock(Blockchain.class), remoteWorldStateArchive);
final RespondingEthPeer.Responder responder = RespondingEthPeer.wrapResponderWithCollector(blockChainResponder, sentMessages);
CompletableFuture<Void> result = downloader.run(null, new FastSyncState(header));
peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone());
assertThat(localStorage.isWorldStateAvailable(stateRoot, header.getHash())).isTrue();
// Check that already enqueued 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(queuedHashes);
// Check that already enqueued requests were not enqueued more than once
for (Bytes32 bytes32 : queuedHashes) {
final Hash hash = Hash.wrap(bytes32);
verify(taskCollection, times(1)).add(argThat((r) -> r.getHash().equals(hash)));
}
// Check that all expected account data was downloaded
assertThat(result).isDone();
final WorldStateArchive localWorldStateArchive = new DefaultWorldStateArchive(localStorage, createPreimageStorage());
final WorldState localWorldState = localWorldStateArchive.get(stateRoot, null).get();
assertAccountsMatch(localWorldState, accounts);
}
use of org.hyperledger.besu.ethereum.trie.Node 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.trie.Node in project besu by hyperledger.
the class StackTrie method commit.
public void commit(final NodeUpdater nodeUpdater) {
if (nbSegments.decrementAndGet() <= 0 && !elements.isEmpty()) {
final List<Bytes> proofs = new ArrayList<>();
final TreeMap<Bytes32, Bytes> keys = new TreeMap<>();
elements.values().forEach(taskElement -> {
proofs.addAll(taskElement.proofs());
keys.putAll(taskElement.keys());
});
final Map<Bytes32, Bytes> proofsEntries = new HashMap<>();
for (Bytes proof : proofs) {
proofsEntries.put(Hash.hash(proof), proof);
}
final InnerNodeDiscoveryManager<Bytes> snapStoredNodeFactory = new InnerNodeDiscoveryManager<>((location, hash) -> Optional.ofNullable(proofsEntries.get(hash)), Function.identity(), Function.identity(), startKeyHash, keys.lastKey(), true);
final MerklePatriciaTrie<Bytes, Bytes> trie = new StoredMerklePatriciaTrie<>(snapStoredNodeFactory, proofs.isEmpty() ? MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH : rootHash);
for (Map.Entry<Bytes32, Bytes> account : keys.entrySet()) {
trie.put(account.getKey(), new SnapPutVisitor<>(snapStoredNodeFactory, account.getValue()));
}
trie.commit(nodeUpdater, (new CommitVisitor<>(nodeUpdater) {
@Override
public void maybeStoreNode(final Bytes location, final Node<Bytes> node) {
if (!node.isHealNeeded()) {
super.maybeStoreNode(location, node);
}
}
}));
}
}
use of org.hyperledger.besu.ethereum.trie.Node in project besu by hyperledger.
the class FastWorldStateDownloaderTest method doesNotRequestKnownAccountTrieNodesFromNetwork.
@Test
public void doesNotRequestKnownAccountTrieNodesFromNetwork() {
// 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 Map<Bytes32, Bytes> allNodes = collectTrieNodesToBeRequestedAfterRoot(remoteStorage, remoteWorldState.rootHash(), 5);
final Set<Bytes32> knownNodes = new HashSet<>();
final Set<Bytes32> unknownNodes = new HashSet<>();
// Sanity check
assertThat(allNodes.size()).isGreaterThan(0);
final Updater localStorageUpdater = localStorage.updater();
final AtomicBoolean storeNode = new AtomicBoolean(true);
allNodes.forEach((nodeHash, node) -> {
if (storeNode.get()) {
localStorageUpdater.putAccountStateTrieNode(null, nodeHash, node);
knownNodes.add(nodeHash);
} else {
unknownNodes.add(nodeHash);
}
storeNode.set(!storeNode.get());
});
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);
final RespondingEthPeer.Responder responder = RespondingEthPeer.wrapResponderWithCollector(blockChainResponder, sentMessages);
respondUntilDone(peers, responder, result);
// 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.trie.Node in project besu by hyperledger.
the class FastWorldStateDownloaderTest method doesNotRequestKnownCodeFromNetwork.
@Test
public void doesNotRequestKnownCodeFromNetwork() {
// Setup "remote" state
final WorldStateArchive remoteWorldStateArchive = createInMemoryWorldStateArchive();
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 contract values
final Map<Bytes32, Bytes> knownCode = new HashMap<>();
accounts.subList(0, 5).forEach(a -> knownCode.put(a.getCodeHash(), a.getCode()));
final Updater localStorageUpdater = localStorage.updater();
knownCode.forEach((bytes32, code) -> localStorageUpdater.putCode(null, code));
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);
final RespondingEthPeer.Responder responder = RespondingEthPeer.wrapResponderWithCollector(blockChainResponder, sentMessages);
respondUntilDone(peers, responder, result);
// Check that known code was not 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(Collections.disjoint(requestedHashes, knownCode.keySet())).isTrue();
// 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);
}
Aggregations