1use crate::{HashBuilder, EMPTY_ROOT_HASH};
2use alloc::vec::Vec;
3use alloy_primitives::B256;
4use alloy_rlp::Encodable;
5use nybbles::Nibbles;
6
7pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize {
9 if i > 0x7f {
10 i
11 } else if i == 0x7f || i + 1 == len {
12 0
13 } else {
14 i + 1
15 }
16}
17
18pub fn ordered_trie_root<T: Encodable>(items: &[T]) -> B256 {
20 ordered_trie_root_with_encoder(items, |item, buf| item.encode(buf))
21}
22
23pub fn ordered_trie_root_with_encoder<T, F>(items: &[T], mut encode: F) -> B256
25where
26 F: FnMut(&T, &mut Vec<u8>),
27{
28 if items.is_empty() {
29 return EMPTY_ROOT_HASH;
30 }
31
32 let mut value_buffer = Vec::new();
33
34 let mut hb = HashBuilder::default();
35 let items_len = items.len();
36 for i in 0..items_len {
37 let index = adjust_index_for_rlp(i, items_len);
38
39 let index_buffer = alloy_rlp::encode_fixed_size(&index);
40
41 value_buffer.clear();
42 encode(&items[index], &mut value_buffer);
43
44 hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer);
45 }
46
47 hb.root()
48}
49
50#[cfg(feature = "ethereum")]
52pub use ethereum::*;
53#[cfg(feature = "ethereum")]
54mod ethereum {
55 use super::*;
56 use crate::TrieAccount;
57 use alloy_primitives::{keccak256, Address, U256};
58
59 pub fn storage_root_unhashed(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
62 storage_root_unsorted(storage.into_iter().map(|(slot, value)| (keccak256(slot), value)))
63 }
64
65 pub fn storage_root_unsorted(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
68 let mut v = Vec::from_iter(storage);
69 v.sort_unstable_by_key(|(key, _)| *key);
70 storage_root(v)
71 }
72
73 pub fn storage_root(storage: impl IntoIterator<Item = (B256, U256)>) -> B256 {
79 let mut hb = HashBuilder::default();
80 for (hashed_slot, value) in storage {
81 hb.add_leaf(
82 Nibbles::unpack(hashed_slot),
83 alloy_rlp::encode_fixed_size(&value).as_ref(),
84 );
85 }
86 hb.root()
87 }
88
89 pub fn state_root_ref_unhashed<'a, A: Into<TrieAccount> + Clone + 'a>(
93 state: impl IntoIterator<Item = (&'a Address, &'a A)>,
94 ) -> B256 {
95 state_root_unsorted(
96 state.into_iter().map(|(address, account)| (keccak256(address), account.clone())),
97 )
98 }
99
100 pub fn state_root_unhashed<A: Into<TrieAccount>>(
104 state: impl IntoIterator<Item = (Address, A)>,
105 ) -> B256 {
106 state_root_unsorted(
107 state.into_iter().map(|(address, account)| (keccak256(address), account)),
108 )
109 }
110
111 pub fn state_root_unsorted<A: Into<TrieAccount>>(
114 state: impl IntoIterator<Item = (B256, A)>,
115 ) -> B256 {
116 let mut vec = Vec::from_iter(state);
117 vec.sort_unstable_by_key(|(key, _)| *key);
118 state_root(vec)
119 }
120
121 pub fn state_root<A: Into<TrieAccount>>(state: impl IntoIterator<Item = (B256, A)>) -> B256 {
129 let mut hb = HashBuilder::default();
130 let mut account_rlp_buf = Vec::new();
131 for (hashed_key, account) in state {
132 account_rlp_buf.clear();
133 account.into().encode(&mut account_rlp_buf);
134 hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf);
135 }
136 hb.root()
137 }
138}