1#![expect(
14 clippy::arithmetic_side_effects,
15 reason = "Found 7 occurrences after enabling the lint."
16)]
17#![expect(
18 clippy::bool_to_int_with_if,
19 reason = "Found 1 occurrences after enabling the lint."
20)]
21#![expect(
22 clippy::indexing_slicing,
23 reason = "Found 13 occurrences after enabling the lint."
24)]
25
26use std::cmp;
27use std::collections::BTreeMap;
28use std::iter::once;
29
30use hash_db::Hasher;
31use rlp::RlpStream;
32
33fn shared_prefix_len<T: Eq>(first: &[T], second: &[T]) -> usize {
34 first
35 .iter()
36 .zip(second.iter())
37 .position(|(f, s)| f != s)
38 .unwrap_or_else(|| cmp::min(first.len(), second.len()))
39}
40
41pub fn ordered_trie_root<H, I>(input: I) -> H::Out
54where
55 I: IntoIterator,
56 I::Item: AsRef<[u8]>,
57 H: Hasher,
58 <H as hash_db::Hasher>::Out: cmp::Ord,
59{
60 trie_root::<H, _, _, _>(
61 input
62 .into_iter()
63 .enumerate()
64 .map(|(i, v)| (rlp::encode(&i), v)),
65 )
66}
67
68pub fn trie_root<H, I, A, B>(input: I) -> H::Out
86where
87 I: IntoIterator<Item = (A, B)>,
88 A: AsRef<[u8]> + Ord,
89 B: AsRef<[u8]>,
90 H: Hasher,
91 <H as hash_db::Hasher>::Out: cmp::Ord,
92{
93 let input = input.into_iter().collect::<BTreeMap<_, _>>();
95
96 let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
97 let mut lens = Vec::with_capacity(input.len() + 1);
98 lens.push(0);
99 for k in input.keys() {
100 for &b in k.as_ref() {
101 nibbles.push(b >> 4);
102 nibbles.push(b & 0x0F);
103 }
104 lens.push(nibbles.len());
105 }
106
107 let input = input
109 .into_iter()
110 .zip(lens.windows(2))
111 .map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
112 .collect::<Vec<_>>();
113
114 let mut stream = RlpStream::new();
115 hash256rlp::<H, _, _>(&input, 0, &mut stream);
116 H::hash(&stream.out())
117}
118
119pub fn sec_trie_root<H, I, A, B>(input: I) -> H::Out
137where
138 I: IntoIterator<Item = (A, B)>,
139 A: AsRef<[u8]>,
140 B: AsRef<[u8]>,
141 H: Hasher,
142 <H as hash_db::Hasher>::Out: cmp::Ord,
143{
144 trie_root::<H, _, _, _>(input.into_iter().map(|(k, v)| (H::hash(k.as_ref()), v)))
145}
146
147fn hex_prefix_encode(nibbles: &[u8], leaf: bool) -> impl Iterator<Item = u8> + '_ {
167 let inlen = nibbles.len();
168 let oddness_factor = inlen % 2;
169
170 let first_byte = {
171 let mut bits = ((inlen as u8 & 1) + (2 * u8::from(leaf))) << 4;
172 if oddness_factor == 1 {
173 bits += nibbles[0];
174 }
175 bits
176 };
177 once(first_byte).chain(
178 nibbles[oddness_factor..]
179 .chunks(2)
180 .map(|ch| (ch[0] << 4) | ch[1]),
181 )
182}
183
184fn hash256rlp<H, A, B>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream)
185where
186 A: AsRef<[u8]>,
187 B: AsRef<[u8]>,
188 H: Hasher,
189{
190 let inlen = input.len();
191
192 if inlen == 0 {
194 stream.append_empty_data();
195 return;
196 }
197
198 let key: &[u8] = input[0].0.as_ref();
200 let value: &[u8] = input[0].1.as_ref();
201
202 if inlen == 1 {
205 stream.begin_list(2);
206 stream.append_iter(hex_prefix_encode(&key[pre_len..], true));
207 stream.append(&value);
208 return;
209 }
210
211 let shared_prefix = input
213 .iter()
214 .skip(1)
216 .fold(key.len(), |acc, (k, _)| {
218 cmp::min(shared_prefix_len(key, k.as_ref()), acc)
219 });
220
221 if shared_prefix > pre_len {
225 stream.begin_list(2);
226 stream.append_iter(hex_prefix_encode(&key[pre_len..shared_prefix], false));
227 hash256aux::<H, _, _>(input, shared_prefix, stream);
228 return;
229 }
230
231 stream.begin_list(17);
234
235 let mut begin = if pre_len == key.len() { 1 } else { 0 };
237
238 for i in 0..16 {
240 let len = input
242 .iter()
243 .skip(begin)
244 .take_while(|pair| pair.0.as_ref()[pre_len] == i)
245 .count();
246
247 match len {
250 0 => {
251 stream.append_empty_data();
252 }
253 _ => hash256aux::<H, _, _>(&input[begin..(begin + len)], pre_len + 1, stream),
254 }
255 begin += len;
256 }
257
258 if pre_len == key.len() {
260 stream.append(&value);
261 } else {
262 stream.append_empty_data();
263 }
264}
265
266fn hash256aux<H, A, B>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream)
267where
268 A: AsRef<[u8]>,
269 B: AsRef<[u8]>,
270 H: Hasher,
271{
272 let mut s = RlpStream::new();
273 hash256rlp::<H, _, _>(input, pre_len, &mut s);
274 let out = s.out();
275 match out.len() {
276 0..=31 => stream.append_raw(&out, 1),
277 _ => stream.append(&H::hash(&out).as_ref()),
278 };
279}
280
281#[cfg(test)]
282mod tests {
283 use super::{hex_prefix_encode, shared_prefix_len, trie_root};
284 use ethereum_types::H256;
285 use hex_literal::hex;
286 use keccak_hasher::KeccakHasher;
287
288 #[test]
289 fn test_hex_prefix_encode() {
290 let v = vec![0, 0, 1, 2, 3, 4, 5];
291 let e = vec![0x10, 0x01, 0x23, 0x45];
292 let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
293 assert_eq!(h, e);
294
295 let v = vec![0, 1, 2, 3, 4, 5];
296 let e = vec![0x00, 0x01, 0x23, 0x45];
297 let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
298 assert_eq!(h, e);
299
300 let v = vec![0, 1, 2, 3, 4, 5];
301 let e = vec![0x20, 0x01, 0x23, 0x45];
302 let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
303 assert_eq!(h, e);
304
305 let v = vec![1, 2, 3, 4, 5];
306 let e = vec![0x31, 0x23, 0x45];
307 let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
308 assert_eq!(h, e);
309
310 let v = vec![1, 2, 3, 4];
311 let e = vec![0x00, 0x12, 0x34];
312 let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
313 assert_eq!(h, e);
314
315 let v = vec![4, 1];
316 let e = vec![0x20, 0x41];
317 let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
318 assert_eq!(h, e);
319 }
320
321 #[test]
322 fn simple_test() {
323 assert_eq!(
324 trie_root::<KeccakHasher, _, _, _>(vec![(
325 b"A",
326 b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]
327 )]),
328 H256::from(hex!(
329 "d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab"
330 ))
331 .as_ref(),
332 );
333 }
334
335 #[test]
336 fn test_triehash_out_of_order() {
337 assert_eq!(
338 trie_root::<KeccakHasher, _, _, _>(vec![
339 (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
340 (vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
341 (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
342 ]),
343 trie_root::<KeccakHasher, _, _, _>(vec![
344 (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
345 (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), (vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
347 ]),
348 );
349 }
350
351 #[test]
352 fn test_shared_prefix() {
353 let a = vec![1, 2, 3, 4, 5, 6];
354 let b = vec![4, 2, 3, 4, 5, 6];
355 assert_eq!(shared_prefix_len(&a, &b), 0);
356 }
357
358 #[test]
359 fn test_shared_prefix2() {
360 let a = vec![1, 2, 3, 3, 5];
361 let b = vec![1, 2, 3];
362 assert_eq!(shared_prefix_len(&a, &b), 3);
363 }
364
365 #[test]
366 fn test_shared_prefix3() {
367 let a = vec![1, 2, 3, 4, 5, 6];
368 let b = vec![1, 2, 3, 4, 5, 6];
369 assert_eq!(shared_prefix_len(&a, &b), 6);
370 }
371}