use of org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue in project besu by hyperledger.
the class StateBackupService method visitAccount.
private TrieIterator.State visitAccount(final Bytes32 nodeKey, final Node<Bytes> node) {
if (node.getValue().isEmpty()) {
return State.CONTINUE;
}
backupStatus.currentAccount = nodeKey;
final Bytes nodeValue = node.getValue().orElse(Hash.EMPTY);
final StateTrieAccountValue account = StateTrieAccountValue.readFrom(new BytesValueRLPInput(nodeValue, false));
final Bytes code = worldStateStorage.getCode(account.getCodeHash(), null).orElse(Bytes.EMPTY);
backupStatus.codeSize.addAndGet(code.size());
final BytesValueRLPOutput accountOutput = new BytesValueRLPOutput();
accountOutput.startList();
// trie hash
accountOutput.writeBytes(nodeKey);
// account rlp
accountOutput.writeBytes(nodeValue);
// code
accountOutput.writeBytes(code);
accountOutput.endList();
try {
accountFileWriter.writeBytes(accountOutput.encoded().toArrayUnsafe());
} catch (final IOException ioe) {
LOG.error("Failure writing backup", ioe);
return State.STOP;
}
// storage is written for each leaf, otherwise the whole trie would have to fit in memory
final StoredMerklePatriciaTrie<Bytes32, Bytes> storageTrie = new StoredMerklePatriciaTrie<>(worldStateStorage::getAccountStateTrieNode, account.getStorageRoot(), Function.identity(), Function.identity());
storageTrie.visitLeafs((storageKey, storageValue) -> visitAccountStorage(storageKey, storageValue, accountFileWriter));
try {
accountFileWriter.writeBytes(ACCOUNT_END_MARKER.toArrayUnsafe());
} catch (final IOException ioe) {
LOG.error("Failure writing backup", ioe);
return State.STOP;
}
backupStatus.accountCount.incrementAndGet();
return State.CONTINUE;
}
use of org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue in project besu by hyperledger.
the class TrieGenerator method generateTrie.
public static MerklePatriciaTrie<Bytes32, Bytes> generateTrie(final WorldStateStorage worldStateStorage, final int nbAccounts) {
final List<Hash> accountHash = new ArrayList<>();
final MerklePatriciaTrie<Bytes32, Bytes> accountStateTrie = emptyAccountStateTrie(worldStateStorage);
// Add some storage values
for (int i = 0; i < nbAccounts; i++) {
final WorldStateStorage.Updater updater = worldStateStorage.updater();
accountHash.add(Hash.wrap(Bytes32.leftPad(Bytes.of(i + 1))));
final MerklePatriciaTrie<Bytes32, Bytes> storageTrie = emptyStorageTrie(worldStateStorage, accountHash.get(i));
writeStorageValue(storageTrie, UInt256.ONE, UInt256.valueOf(2L));
writeStorageValue(storageTrie, UInt256.valueOf(2L), UInt256.valueOf(4L));
writeStorageValue(storageTrie, UInt256.valueOf(3L), UInt256.valueOf(6L));
int accountIndex = i;
storageTrie.commit((location, hash, value) -> updater.putAccountStorageTrieNode(accountHash.get(accountIndex), location, hash, value));
final Bytes code = Bytes32.leftPad(Bytes.of(i + 10));
final Hash codeHash = Hash.hash(code);
final StateTrieAccountValue accountValue = new StateTrieAccountValue(1L, Wei.of(2L), Hash.wrap(storageTrie.getRootHash()), codeHash);
accountStateTrie.put(accountHash.get(i), RLP.encode(accountValue::writeTo));
accountStateTrie.commit(updater::putAccountStateTrieNode);
updater.putCode(codeHash, code);
// Persist updates
updater.commit();
}
return accountStateTrie;
}
use of org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue 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.StateTrieAccountValue in project besu by hyperledger.
the class TrieLogLayer method writeTo.
void writeTo(final RLPOutput output) {
freeze();
final Set<Address> addresses = new TreeSet<>();
addresses.addAll(accounts.keySet());
addresses.addAll(code.keySet());
addresses.addAll(storage.keySet());
// container
output.startList();
output.writeBytes(blockHash);
for (final Address address : addresses) {
// this change
output.startList();
output.writeBytes(address);
final BonsaiValue<StateTrieAccountValue> accountChange = accounts.get(address);
if (accountChange == null || accountChange.isUnchanged()) {
output.writeNull();
} else {
accountChange.writeRlp(output, (o, sta) -> sta.writeTo(o));
}
final BonsaiValue<Bytes> codeChange = code.get(address);
if (codeChange == null || codeChange.isUnchanged()) {
output.writeNull();
} else {
codeChange.writeRlp(output, RLPOutput::writeBytes);
}
final Map<Hash, BonsaiValue<UInt256>> storageChanges = storage.get(address);
if (storageChanges == null) {
output.writeNull();
} else {
output.startList();
for (final Map.Entry<Hash, BonsaiValue<UInt256>> storageChangeEntry : storageChanges.entrySet()) {
output.startList();
output.writeBytes(storageChangeEntry.getKey());
storageChangeEntry.getValue().writeInnerRlp(output, RLPOutput::writeUInt256Scalar);
output.endList();
}
output.endList();
}
// TODO write trie nodes
// this change
output.endList();
}
// container
output.endList();
}
use of org.hyperledger.besu.ethereum.worldstate.StateTrieAccountValue in project besu by hyperledger.
the class WorldStateProofProviderTest method getProofWhenWorldStateAvailable.
@Test
public void getProofWhenWorldStateAvailable() {
final Hash addressHash = Hash.hash(address);
final MerklePatriciaTrie<Bytes32, Bytes> worldStateTrie = emptyWorldStateTrie(addressHash);
final MerklePatriciaTrie<Bytes32, Bytes> storageTrie = emptyStorageTrie();
final WorldStateStorage.Updater updater = worldStateStorage.updater();
// Add some storage values
writeStorageValue(storageTrie, UInt256.ONE, UInt256.valueOf(2L));
writeStorageValue(storageTrie, UInt256.valueOf(2L), UInt256.valueOf(4L));
writeStorageValue(storageTrie, UInt256.valueOf(3L), UInt256.valueOf(6L));
// Save to Storage
storageTrie.commit((location, hash, value) -> updater.putAccountStorageTrieNode(addressHash, location, hash, value));
// Define account value
final Hash codeHash = Hash.hash(Bytes.fromHexString("0x1122"));
final StateTrieAccountValue accountValue = new StateTrieAccountValue(1L, Wei.of(2L), Hash.wrap(storageTrie.getRootHash()), codeHash);
// Save to storage
worldStateTrie.put(addressHash, RLP.encode(accountValue::writeTo));
worldStateTrie.commit(updater::putAccountStateTrieNode);
// Persist updates
updater.commit();
final List<UInt256> storageKeys = Arrays.asList(UInt256.ONE, UInt256.valueOf(3L), UInt256.valueOf(6L));
final Optional<WorldStateProof> accountProof = worldStateProofProvider.getAccountProof(Hash.wrap(worldStateTrie.getRootHash()), address, storageKeys);
assertThat(accountProof).isPresent();
Assertions.assertThat(accountProof.get().getStateTrieAccountValue()).isEqualToComparingFieldByField(accountValue);
assertThat(accountProof.get().getAccountProof().size()).isGreaterThanOrEqualTo(1);
// Check storage fields
assertThat(accountProof.get().getStorageKeys()).isEqualTo(storageKeys);
// Check key 1
UInt256 storageKey = UInt256.ONE;
assertThat(accountProof.get().getStorageValue(storageKey)).isEqualTo(UInt256.valueOf(2L));
assertThat(accountProof.get().getStorageProof(storageKey).size()).isGreaterThanOrEqualTo(1);
// Check key 3
storageKey = UInt256.valueOf(3L);
assertThat(accountProof.get().getStorageValue(storageKey)).isEqualTo(UInt256.valueOf(6L));
assertThat(accountProof.get().getStorageProof(storageKey).size()).isGreaterThanOrEqualTo(1);
// Check key 6
storageKey = UInt256.valueOf(6L);
assertThat(accountProof.get().getStorageValue(storageKey)).isEqualTo(UInt256.ZERO);
assertThat(accountProof.get().getStorageProof(storageKey).size()).isGreaterThanOrEqualTo(1);
}
Aggregations