anvil/eth/backend/mem/
state.rs

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