anvil/eth/backend/mem/
state.rs1use 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
19pub fn state_root(accounts: &AddressMap<DbAccount>) -> B256 {
21 build_root(trie_accounts(accounts))
22}
23
24pub fn storage_root(storage: &HashMap<U256, U256>) -> B256 {
26 build_root(trie_storage(storage))
27}
28
29pub 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
43pub 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
57pub 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}