revme/cmd/statetest/
merkle_trie.rs

1use std::convert::Infallible;
2
3use alloy_rlp::{RlpEncodable, RlpMaxEncodedLen};
4use context::result::{EVMError, ExecutionResult, HaltReason, InvalidTransaction};
5use database::{EmptyDB, PlainAccount, State};
6use hash_db::Hasher;
7use plain_hasher::PlainHasher;
8use revm::primitives::{keccak256, Address, Log, B256, U256};
9use triehash::sec_trie_root;
10
11pub struct TestValidationResult {
12    pub logs_root: B256,
13    pub state_root: B256,
14}
15
16pub fn compute_test_roots(
17    exec_result: &Result<ExecutionResult<HaltReason>, EVMError<Infallible, InvalidTransaction>>,
18    db: &State<EmptyDB>,
19) -> TestValidationResult {
20    TestValidationResult {
21        logs_root: log_rlp_hash(exec_result.as_ref().map(|r| r.logs()).unwrap_or_default()),
22        state_root: state_merkle_trie_root(db.cache.trie_account()),
23    }
24}
25
26pub fn log_rlp_hash(logs: &[Log]) -> B256 {
27    let mut out = Vec::with_capacity(alloy_rlp::list_length(logs));
28    alloy_rlp::encode_list(logs, &mut out);
29    keccak256(&out)
30}
31
32pub fn state_merkle_trie_root<'a>(
33    accounts: impl IntoIterator<Item = (Address, &'a PlainAccount)>,
34) -> B256 {
35    trie_root(accounts.into_iter().map(|(address, acc)| {
36        (
37            address,
38            alloy_rlp::encode_fixed_size(&TrieAccount::new(acc)),
39        )
40    }))
41}
42
43#[derive(RlpEncodable, RlpMaxEncodedLen)]
44struct TrieAccount {
45    nonce: u64,
46    balance: U256,
47    root_hash: B256,
48    code_hash: B256,
49}
50
51impl TrieAccount {
52    fn new(acc: &PlainAccount) -> Self {
53        Self {
54            nonce: acc.info.nonce,
55            balance: acc.info.balance,
56            root_hash: sec_trie_root::<KeccakHasher, _, _, _>(
57                acc.storage
58                    .iter()
59                    .filter(|(_k, &v)| !v.is_zero())
60                    .map(|(k, v)| (k.to_be_bytes::<32>(), alloy_rlp::encode_fixed_size(v))),
61            ),
62            code_hash: acc.info.code_hash,
63        }
64    }
65}
66
67#[inline]
68pub fn trie_root<I, A, B>(input: I) -> B256
69where
70    I: IntoIterator<Item = (A, B)>,
71    A: AsRef<[u8]>,
72    B: AsRef<[u8]>,
73{
74    sec_trie_root::<KeccakHasher, _, _, _>(input)
75}
76
77#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
78pub struct KeccakHasher;
79
80impl Hasher for KeccakHasher {
81    type Out = B256;
82    type StdHasher = PlainHasher;
83    const LENGTH: usize = 32;
84
85    #[inline]
86    fn hash(x: &[u8]) -> Self::Out {
87        keccak256(x)
88    }
89}