reth_primitives_traits/
proofs.rs

1//! Helper function for calculating Merkle proofs and hashes.
2pub use alloy_trie::root::ordered_trie_root_with_encoder;
3
4pub use alloy_consensus::proofs::calculate_receipt_root;
5
6/// Calculate a transaction root.
7///
8/// `(rlp(index), encoded(tx))` pairs.
9#[doc(inline)]
10pub use alloy_consensus::proofs::calculate_transaction_root;
11
12/// Calculates the root hash of the withdrawals.
13#[doc(inline)]
14pub use alloy_consensus::proofs::calculate_withdrawals_root;
15
16/// Calculates the root hash for ommer/uncle headers.
17#[doc(inline)]
18pub use alloy_consensus::proofs::calculate_ommers_root;
19
20#[cfg(test)]
21mod tests {
22    use alloy_consensus::EMPTY_ROOT_HASH;
23    use alloy_genesis::GenesisAccount;
24    use alloy_primitives::{b256, hex_literal::hex, Address, B256, U256};
25    use alloy_trie::root::{state_root_ref_unhashed, state_root_unhashed};
26    use reth_chainspec::{HOLESKY, MAINNET, SEPOLIA};
27    use std::collections::HashMap;
28
29    #[test]
30    fn check_empty_state_root() {
31        let genesis_alloc = HashMap::<Address, GenesisAccount>::new();
32        let root = state_root_unhashed(genesis_alloc);
33        assert_eq!(root, EMPTY_ROOT_HASH);
34    }
35
36    #[test]
37    fn test_simple_account_state_root() {
38        // each fixture specifies an address and expected root hash - the address is initialized
39        // with a maximum balance, and is the only account in the state.
40        // these test cases are generated by using geth with a custom genesis.json (with a single
41        // account that has max balance)
42        let fixtures: Vec<(Address, B256)> = vec![
43            (
44                hex!("9fe4abd71ad081f091bd06dd1c16f7e92927561e").into(),
45                hex!("4b35be4231841d212ce2fa43aedbddeadd6eb7d420195664f9f0d55629db8c32").into(),
46            ),
47            (
48                hex!("c2ba9d87f8be0ade00c60d3656c1188e008fbfa2").into(),
49                hex!("e1389256c47d63df8856d7729dec9dc2dae074a7f0cbc49acad1cf7b29f7fe94").into(),
50            ),
51        ];
52
53        for (test_addr, expected_root) in fixtures {
54            let mut genesis_alloc = HashMap::new();
55            genesis_alloc
56                .insert(test_addr, GenesisAccount { balance: U256::MAX, ..Default::default() });
57
58            let root = state_root_unhashed(genesis_alloc);
59
60            assert_eq!(root, expected_root);
61        }
62    }
63
64    #[test]
65    fn test_chain_state_roots() {
66        let expected_mainnet_state_root =
67            b256!("0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544");
68        let calculated_mainnet_state_root = state_root_ref_unhashed(&MAINNET.genesis.alloc);
69        assert_eq!(
70            expected_mainnet_state_root, calculated_mainnet_state_root,
71            "mainnet state root mismatch"
72        );
73
74        let expected_sepolia_state_root =
75            b256!("0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494");
76        let calculated_sepolia_state_root = state_root_ref_unhashed(&SEPOLIA.genesis.alloc);
77        assert_eq!(
78            expected_sepolia_state_root, calculated_sepolia_state_root,
79            "sepolia state root mismatch"
80        );
81
82        let expected_holesky_state_root =
83            b256!("0x69d8c9d72f6fa4ad42d4702b433707212f90db395eb54dc20bc85de253788783");
84        let calculated_holesky_state_root = state_root_ref_unhashed(&HOLESKY.genesis.alloc);
85        assert_eq!(
86            expected_holesky_state_root, calculated_holesky_state_root,
87            "holesky state root mismatch"
88        );
89    }
90}