Skip to main content

revmc_statetest/
merkle_trie.rs

1use std::convert::Infallible;
2
3use alloy_trie::{root::storage_root_unhashed, HashBuilder, Nibbles, TrieAccount};
4use revm::{
5    context::result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction},
6    database::{bal::EvmDatabaseError, EmptyDB, PlainAccount, State},
7    primitives::{keccak256, Address, Log, B256},
8};
9
10pub struct TestValidationResult {
11    pub logs_root: B256,
12    pub state_root: B256,
13}
14
15pub fn compute_test_roots(
16    exec_result: &Result<
17        ExecutionResult<HaltReason>,
18        EVMError<EvmDatabaseError<Infallible>, InvalidTransaction>,
19    >,
20    db: &State<EmptyDB>,
21) -> TestValidationResult {
22    TestValidationResult {
23        logs_root: log_rlp_hash(exec_result.as_ref().map(|r| r.logs()).unwrap_or_default()),
24        state_root: state_merkle_trie_root(db.cache.trie_account()),
25    }
26}
27
28pub fn log_rlp_hash(logs: &[Log]) -> B256 {
29    let mut out = Vec::with_capacity(alloy_rlp::list_length(logs));
30    alloy_rlp::encode_list(logs, &mut out);
31    keccak256(&out)
32}
33
34pub fn state_merkle_trie_root<'a>(
35    accounts: impl IntoIterator<Item = (Address, &'a PlainAccount)>,
36) -> B256 {
37    let mut vec: Vec<_> = accounts
38        .into_iter()
39        .map(|(address, acc)| {
40            let storage_root = storage_root_unhashed(
41                acc.storage
42                    .iter()
43                    .filter(|(_k, &v)| !v.is_zero())
44                    .map(|(k, v)| (B256::from(*k), *v)),
45            );
46            (
47                keccak256(address),
48                TrieAccount {
49                    nonce: acc.info.nonce,
50                    balance: acc.info.balance,
51                    storage_root,
52                    code_hash: acc.info.code_hash,
53                },
54            )
55        })
56        .collect();
57    vec.sort_unstable_by_key(|(key, _)| *key);
58
59    let mut hb = HashBuilder::default();
60    let mut account_rlp_buf = Vec::new();
61    for (hashed_key, account) in vec {
62        account_rlp_buf.clear();
63        alloy_rlp::Encodable::encode(&account, &mut account_rlp_buf);
64        hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf);
65    }
66    hb.root()
67}