anvil/eth/backend/mem/
state.rs

1//! Support for generating the state root for memdb storage
2
3use alloy_primitives::{Address, B256, U256, keccak256, map::HashMap};
4use alloy_rlp::Encodable;
5use alloy_trie::{HashBuilder, Nibbles};
6use revm::{database::DbAccount, state::AccountInfo};
7
8pub fn build_root(values: impl IntoIterator<Item = (Nibbles, Vec<u8>)>) -> B256 {
9    let mut builder = HashBuilder::default();
10    for (key, value) in values {
11        builder.add_leaf(key, value.as_ref());
12    }
13    builder.root()
14}
15
16/// Builds state root from the given accounts
17pub fn state_root(accounts: &HashMap<Address, DbAccount>) -> B256 {
18    build_root(trie_accounts(accounts))
19}
20
21/// Builds storage root from the given storage
22pub fn storage_root(storage: &HashMap<U256, U256>) -> B256 {
23    build_root(trie_storage(storage))
24}
25
26/// Builds iterator over stored key-value pairs ready for storage trie root calculation.
27pub fn trie_storage(storage: &HashMap<U256, U256>) -> Vec<(Nibbles, Vec<u8>)> {
28    let mut storage = storage
29        .iter()
30        .map(|(key, value)| {
31            let data = alloy_rlp::encode(value);
32            (Nibbles::unpack(keccak256(key.to_be_bytes::<32>())), data)
33        })
34        .collect::<Vec<_>>();
35    storage.sort_by(|(key1, _), (key2, _)| key1.cmp(key2));
36
37    storage
38}
39
40/// Builds iterator over stored key-value pairs ready for account trie root calculation.
41pub fn trie_accounts(accounts: &HashMap<Address, DbAccount>) -> Vec<(Nibbles, Vec<u8>)> {
42    let mut accounts = accounts
43        .iter()
44        .map(|(address, account)| {
45            let data = trie_account_rlp(&account.info, &account.storage);
46            (Nibbles::unpack(keccak256(*address)), data)
47        })
48        .collect::<Vec<_>>();
49    accounts.sort_by(|(key1, _), (key2, _)| key1.cmp(key2));
50
51    accounts
52}
53
54/// Returns the RLP for this account.
55pub fn trie_account_rlp(info: &AccountInfo, storage: &HashMap<U256, U256>) -> Vec<u8> {
56    let mut out: Vec<u8> = Vec::new();
57    let list: [&dyn Encodable; 4] =
58        [&info.nonce, &info.balance, &storage_root(storage), &info.code_hash];
59
60    alloy_rlp::encode_list::<_, dyn Encodable>(&list, &mut out);
61
62    out
63}