revme/cmd/statetest/
merkle_trie.rs

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