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