anvil/eth/backend/mem/
state.rs1use 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
16pub fn state_root(accounts: &HashMap<Address, DbAccount>) -> B256 {
18 build_root(trie_accounts(accounts))
19}
20
21pub fn storage_root(storage: &HashMap<U256, U256>) -> B256 {
23 build_root(trie_storage(storage))
24}
25
26pub 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
40pub 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
54pub 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}