alloy_trie/hash_builder/
mod.rs

1//! The implementation of the hash builder.
2
3use super::{
4    BranchNodeCompact, EMPTY_ROOT_HASH, Nibbles, TrieMask,
5    nodes::{BranchNodeRef, ExtensionNodeRef, LeafNodeRef},
6    proof::{ProofNodes, ProofRetainer},
7};
8use crate::{HashMap, nodes::RlpNode, proof::AddedRemovedKeys};
9use alloc::vec::Vec;
10use alloy_primitives::{B256, keccak256};
11use core::cmp;
12use tracing::trace;
13
14mod value;
15pub use value::{HashBuilderValue, HashBuilderValueRef};
16
17/// A component used to construct the root hash of the trie.
18///
19/// The primary purpose of a Hash Builder is to build the Merkle proof that is essential for
20/// verifying the integrity and authenticity of the trie's contents. It achieves this by
21/// constructing the root hash from the hashes of child nodes according to specific rules, depending
22/// on the type of the node (branch, extension, or leaf).
23///
24/// Here's an overview of how the Hash Builder works for each type of node:
25///  * Branch Node: The Hash Builder combines the hashes of all the child nodes of the branch node,
26///    using a cryptographic hash function like SHA-256. The child nodes' hashes are concatenated
27///    and hashed, and the result is considered the hash of the branch node. The process is repeated
28///    recursively until the root hash is obtained.
29///  * Extension Node: In the case of an extension node, the Hash Builder first encodes the node's
30///    shared nibble path, followed by the hash of the next child node. It concatenates these values
31///    and then computes the hash of the resulting data, which represents the hash of the extension
32///    node.
33///  * Leaf Node: For a leaf node, the Hash Builder first encodes the key-path and the value of the
34///    leaf node. It then concatenates theĀ encoded key-path and value, and computes the hash of this
35///    concatenated data, which represents the hash of the leaf node.
36///
37/// The Hash Builder operates recursively, starting from the bottom of the trie and working its way
38/// up, combining the hashes of child nodes and ultimately generating the root hash. The root hash
39/// can then be used to verify the integrity and authenticity of the trie's data by constructing and
40/// verifying Merkle proofs.
41#[derive(Debug, Clone)]
42#[allow(missing_docs)]
43pub struct HashBuilder<K = AddedRemovedKeys> {
44    pub key: Nibbles,
45    pub value: HashBuilderValue,
46    pub stack: Vec<RlpNode>,
47
48    pub state_masks: Vec<TrieMask>,
49    pub tree_masks: Vec<TrieMask>,
50    pub hash_masks: Vec<TrieMask>,
51
52    pub stored_in_database: bool,
53
54    pub updated_branch_nodes: Option<HashMap<Nibbles, BranchNodeCompact>>,
55    pub proof_retainer: Option<ProofRetainer<K>>,
56
57    pub rlp_buf: Vec<u8>,
58}
59
60impl Default for HashBuilder {
61    fn default() -> Self {
62        Self {
63            key: Default::default(),
64            value: Default::default(),
65            stack: Default::default(),
66            state_masks: Default::default(),
67            tree_masks: Default::default(),
68            hash_masks: Default::default(),
69            stored_in_database: Default::default(),
70            updated_branch_nodes: None,
71            proof_retainer: None,
72            rlp_buf: Default::default(),
73        }
74    }
75}
76
77impl<K> HashBuilder<K> {
78    /// Enables the Hash Builder to store updated branch nodes.
79    ///
80    /// Call [HashBuilder::split] to get the updates to branch nodes.
81    pub fn with_updates(mut self, retain_updates: bool) -> Self {
82        self.set_updates(retain_updates);
83        self
84    }
85
86    /// Enable specified proof retainer.
87    pub fn with_proof_retainer<K2>(self, retainer: ProofRetainer<K2>) -> HashBuilder<K2> {
88        HashBuilder {
89            key: self.key,
90            value: self.value,
91            stack: self.stack,
92            state_masks: self.state_masks,
93            tree_masks: self.tree_masks,
94            hash_masks: self.hash_masks,
95            stored_in_database: self.stored_in_database,
96            updated_branch_nodes: self.updated_branch_nodes,
97            proof_retainer: Some(retainer),
98            rlp_buf: self.rlp_buf,
99        }
100    }
101
102    /// Enables the Hash Builder to store updated branch nodes.
103    ///
104    /// Call [HashBuilder::split] to get the updates to branch nodes.
105    pub fn set_updates(&mut self, retain_updates: bool) {
106        if retain_updates {
107            self.updated_branch_nodes = Some(HashMap::default());
108        }
109    }
110}
111
112impl<K: AsRef<AddedRemovedKeys>> HashBuilder<K> {
113    /// Splits the [HashBuilder] into a [HashBuilder] and hash builder updates.
114    pub fn split(mut self) -> (Self, HashMap<Nibbles, BranchNodeCompact>) {
115        let updates = self.updated_branch_nodes.take();
116        (self, updates.unwrap_or_default())
117    }
118
119    /// Take and return retained proof nodes.
120    pub fn take_proof_nodes(&mut self) -> ProofNodes {
121        self.proof_retainer.take().map(ProofRetainer::into_proof_nodes).unwrap_or_default()
122    }
123
124    /// The number of total updates accrued.
125    /// Returns `0` if [Self::with_updates] was not called.
126    pub fn updates_len(&self) -> usize {
127        self.updated_branch_nodes.as_ref().map(|u| u.len()).unwrap_or(0)
128    }
129
130    /// Print the current stack of the Hash Builder.
131    #[cfg(feature = "std")]
132    pub fn print_stack(&self) {
133        println!("============ STACK ===============");
134        for item in &self.stack {
135            println!("{}", alloy_primitives::hex::encode(item));
136        }
137        println!("============ END STACK ===============");
138    }
139
140    /// Adds a new leaf element and its value to the trie hash builder.
141    ///
142    /// # Panics
143    ///
144    /// Panics if the new key does not come after the current key.
145    pub fn add_leaf(&mut self, key: Nibbles, value: &[u8]) {
146        assert!(key > self.key, "add_leaf key {:?} self.key {:?}", key, self.key);
147        self.add_leaf_unchecked(key, value);
148    }
149
150    /// Adds a new leaf element and its value to the trie hash builder,
151    /// without checking the order of the new key. This is only for
152    /// performance-critical usage that guarantees keys are inserted
153    /// in sorted order.
154    pub fn add_leaf_unchecked(&mut self, key: Nibbles, value: &[u8]) {
155        debug_assert!(key > self.key, "add_leaf_unchecked key {:?} self.key {:?}", key, self.key);
156        if !self.key.is_empty() {
157            self.update(&key);
158        }
159        self.set_key_value(key, HashBuilderValueRef::Bytes(value));
160    }
161
162    /// Adds a new branch element and its hash to the trie hash builder.
163    pub fn add_branch(&mut self, key: Nibbles, value: B256, stored_in_database: bool) {
164        assert!(
165            key > self.key || (self.key.is_empty() && key.is_empty()),
166            "add_branch key {:?} self.key {:?}",
167            key,
168            self.key
169        );
170        if !self.key.is_empty() {
171            self.update(&key);
172        } else if key.is_empty() {
173            self.stack.push(RlpNode::word_rlp(&value));
174        }
175        self.set_key_value(key, HashBuilderValueRef::Hash(&value));
176        self.stored_in_database = stored_in_database;
177    }
178
179    /// Returns the current root hash of the trie builder.
180    pub fn root(&mut self) -> B256 {
181        // Clears the internal state
182        if !self.key.is_empty() {
183            self.update(&Nibbles::default());
184            self.key.clear();
185            self.value.clear();
186        }
187        let root = self.current_root();
188        if root == EMPTY_ROOT_HASH {
189            if let Some(proof_retainer) = self.proof_retainer.as_mut() {
190                proof_retainer.retain_empty_root_proof();
191            }
192        }
193        root
194    }
195
196    #[inline]
197    fn set_key_value(&mut self, key: Nibbles, value: HashBuilderValueRef<'_>) {
198        self.log_key_value("old value");
199        self.key = key;
200        self.value.set_from_ref(value);
201        self.log_key_value("new value");
202    }
203
204    fn log_key_value(&self, msg: &str) {
205        trace!(target: "trie::hash_builder",
206            key = ?self.key,
207            value = ?self.value,
208            "{msg}",
209        );
210    }
211
212    fn current_root(&self) -> B256 {
213        if let Some(node_ref) = self.stack.last() {
214            if let Some(hash) = node_ref.as_hash() { hash } else { keccak256(node_ref) }
215        } else {
216            EMPTY_ROOT_HASH
217        }
218    }
219
220    /// Given a new element, it appends it to the stack and proceeds to loop through the stack state
221    /// and convert the nodes it can into branch / extension nodes and hash them. This ensures
222    /// that the top of the stack always contains the merkle root corresponding to the trie
223    /// built so far.
224    fn update(&mut self, succeeding: &Nibbles) {
225        let mut build_extensions = false;
226        // current / self.key is always the latest added element in the trie
227        let mut current = self.key;
228        debug_assert!(!current.is_empty());
229
230        trace!(target: "trie::hash_builder", ?current, ?succeeding, "updating merkle tree");
231
232        let mut i = 0usize;
233        loop {
234            let _span = tracing::trace_span!(target: "trie::hash_builder", "loop", i, ?current, build_extensions).entered();
235
236            let preceding_exists = !self.state_masks.is_empty();
237            let preceding_len = self.state_masks.len().saturating_sub(1);
238
239            let common_prefix_len = succeeding.common_prefix_length(&current);
240            let len = cmp::max(preceding_len, common_prefix_len);
241            assert!(len < current.len(), "len {} current.len {}", len, current.len());
242
243            trace!(
244                target: "trie::hash_builder",
245                ?len,
246                ?common_prefix_len,
247                ?preceding_len,
248                preceding_exists,
249                "prefix lengths after comparing keys"
250            );
251
252            // Adjust the state masks for branch calculation
253            let extra_digit = current.get_unchecked(len);
254            if self.state_masks.len() <= len {
255                let new_len = len + 1;
256                trace!(target: "trie::hash_builder", new_len, old_len = self.state_masks.len(), "scaling state masks to fit");
257                self.state_masks.resize(new_len, TrieMask::default());
258            }
259            self.state_masks[len] |= TrieMask::from_nibble(extra_digit);
260            trace!(
261                target: "trie::hash_builder",
262                ?extra_digit,
263                state_masks = ?self.state_masks,
264            );
265
266            // Adjust the tree masks for exporting to the DB
267            if self.tree_masks.len() < current.len() {
268                self.resize_masks(current.len());
269            }
270
271            let mut len_from = len;
272            if !succeeding.is_empty() || preceding_exists {
273                len_from += 1;
274            }
275            trace!(target: "trie::hash_builder", "skipping {len_from} nibbles");
276
277            // The key without the common prefix
278            let short_node_key = current.slice(len_from..);
279            trace!(target: "trie::hash_builder", ?short_node_key);
280
281            // Concatenate the 2 nodes together
282            if !build_extensions {
283                match self.value.as_ref() {
284                    HashBuilderValueRef::Bytes(leaf_value) => {
285                        let leaf_node = LeafNodeRef::new(&short_node_key, leaf_value);
286                        self.rlp_buf.clear();
287                        let rlp = leaf_node.rlp(&mut self.rlp_buf);
288
289                        let path = current.slice(..len_from);
290                        trace!(
291                            target: "trie::hash_builder",
292                            ?path,
293                            ?leaf_node,
294                            ?rlp,
295                            "pushing leaf node",
296                        );
297                        self.stack.push(rlp);
298
299                        if let Some(proof_retainer) = self.proof_retainer.as_mut() {
300                            proof_retainer.retain_leaf_proof(&path, &self.rlp_buf)
301                        }
302                    }
303                    HashBuilderValueRef::Hash(hash) => {
304                        trace!(target: "trie::hash_builder", ?hash, "pushing branch node hash");
305                        self.stack.push(RlpNode::word_rlp(hash));
306
307                        if self.stored_in_database {
308                            self.tree_masks[current.len() - 1] |=
309                                TrieMask::from_nibble(current.last().unwrap());
310                        }
311                        self.hash_masks[current.len() - 1] |=
312                            TrieMask::from_nibble(current.last().unwrap());
313
314                        build_extensions = true;
315                    }
316                }
317            }
318
319            if build_extensions && !short_node_key.is_empty() {
320                self.update_masks(&current, len_from);
321                let stack_last = self.stack.pop().expect("there should be at least one stack item");
322                let extension_node = ExtensionNodeRef::new(&short_node_key, &stack_last);
323
324                self.rlp_buf.clear();
325                let rlp = extension_node.rlp(&mut self.rlp_buf);
326
327                let path = current.slice(..len_from);
328                trace!(
329                    target: "trie::hash_builder",
330                    ?path,
331                    ?extension_node,
332                    ?rlp,
333                    "pushing extension node",
334                );
335                self.stack.push(rlp);
336
337                if let Some(proof_retainer) = self.proof_retainer.as_mut() {
338                    proof_retainer.retain_extension_proof(&path, &short_node_key, &self.rlp_buf)
339                }
340
341                self.resize_masks(len_from);
342            }
343
344            if preceding_len <= common_prefix_len && !succeeding.is_empty() {
345                trace!(target: "trie::hash_builder", "no common prefix to create branch nodes from, returning");
346                return;
347            }
348
349            // Insert branch nodes in the stack
350            if !succeeding.is_empty() || preceding_exists {
351                // Pushes the corresponding branch node to the stack
352                let children = self.push_branch_node(&current, len);
353                // Need to store the branch node in an efficient format outside of the hash builder
354                self.store_branch_node(&current, len, children);
355            }
356
357            self.state_masks.resize(len, TrieMask::default());
358            self.resize_masks(len);
359
360            if preceding_len == 0 {
361                trace!(target: "trie::hash_builder", "0 or 1 state masks means we have no more elements to process");
362                return;
363            }
364
365            current.truncate(preceding_len);
366            trace!(target: "trie::hash_builder", ?current, "truncated nibbles to {} bytes", preceding_len);
367
368            trace!(target: "trie::hash_builder", state_masks = ?self.state_masks, "popping empty state masks");
369            while self.state_masks.last() == Some(&TrieMask::default()) {
370                self.state_masks.pop();
371            }
372
373            build_extensions = true;
374
375            i += 1;
376        }
377    }
378
379    /// Given the size of the longest common prefix, it proceeds to create a branch node
380    /// from the state mask and existing stack state, and store its RLP to the top of the stack,
381    /// after popping all the relevant elements from the stack.
382    ///
383    /// Returns the hashes of the children of the branch node, only if `updated_branch_nodes` is
384    /// enabled.
385    fn push_branch_node(&mut self, current: &Nibbles, len: usize) -> Vec<B256> {
386        let state_mask = self.state_masks[len];
387        let hash_mask = self.hash_masks[len];
388        let branch_node = BranchNodeRef::new(&self.stack, state_mask);
389        // Avoid calculating this value if it's not needed.
390        let children = if self.updated_branch_nodes.is_some() {
391            branch_node.child_hashes(hash_mask).collect()
392        } else {
393            vec![]
394        };
395
396        self.rlp_buf.clear();
397        let rlp = branch_node.rlp(&mut self.rlp_buf);
398        let path = current.slice(..len);
399        trace!(
400            target: "trie::hash_builder",
401            ?path,
402            ?branch_node,
403            ?rlp,
404            "pushing branch node",
405        );
406
407        if let Some(proof_retainer) = self.proof_retainer.as_mut() {
408            proof_retainer.retain_branch_proof(&path, state_mask, &self.rlp_buf);
409        }
410
411        // Clears the stack from the branch node elements
412        let first_child_idx = self.stack.len() - state_mask.count_ones() as usize;
413        trace!(
414            target: "trie::hash_builder",
415            new_len = first_child_idx,
416            old_len = self.stack.len(),
417            "resizing stack to prepare branch node"
418        );
419        self.stack.resize_with(first_child_idx, Default::default);
420
421        self.stack.push(rlp);
422        children
423    }
424
425    /// Given the current nibble prefix and the highest common prefix length, proceeds
426    /// to update the masks for the next level and store the branch node and the
427    /// masks in the database. We will use that when consuming the intermediate nodes
428    /// from the database to efficiently build the trie.
429    fn store_branch_node(&mut self, current: &Nibbles, len: usize, children: Vec<B256>) {
430        if len > 0 {
431            let parent_index = len - 1;
432            self.hash_masks[parent_index] |=
433                TrieMask::from_nibble(current.get_unchecked(parent_index));
434        }
435
436        let store_in_db_trie = !self.tree_masks[len].is_empty() || !self.hash_masks[len].is_empty();
437        if store_in_db_trie {
438            if len > 0 {
439                let parent_index = len - 1;
440                self.tree_masks[parent_index] |=
441                    TrieMask::from_nibble(current.get_unchecked(parent_index));
442            }
443
444            if self.updated_branch_nodes.is_some() {
445                let common_prefix = current.slice(..len);
446                let node = BranchNodeCompact::new(
447                    self.state_masks[len],
448                    self.tree_masks[len],
449                    self.hash_masks[len],
450                    children,
451                    (len == 0).then(|| self.current_root()),
452                );
453                self.updated_branch_nodes.as_mut().unwrap().insert(common_prefix, node);
454            }
455        }
456    }
457
458    fn update_masks(&mut self, current: &Nibbles, len_from: usize) {
459        if len_from > 0 {
460            let flag = TrieMask::from_nibble(current.get_unchecked(len_from - 1));
461
462            self.hash_masks[len_from - 1] &= !flag;
463
464            if !self.tree_masks[current.len() - 1].is_empty() {
465                self.tree_masks[len_from - 1] |= flag;
466            }
467        }
468    }
469
470    fn resize_masks(&mut self, new_len: usize) {
471        trace!(
472            target: "trie::hash_builder",
473            new_len,
474            old_tree_mask_len = self.tree_masks.len(),
475            old_hash_mask_len = self.hash_masks.len(),
476            "resizing tree/hash masks"
477        );
478        self.tree_masks.resize(new_len, TrieMask::default());
479        self.hash_masks.resize(new_len, TrieMask::default());
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    use super::*;
486    use crate::{nodes::LeafNode, triehash_trie_root};
487    use alloc::collections::BTreeMap;
488    use alloy_primitives::{U256, b256, hex};
489    use alloy_rlp::Encodable;
490
491    // Hashes the keys, RLP encodes the values, compares the trie builder with the upstream root.
492    fn assert_hashed_trie_root<'a, I, K>(iter: I)
493    where
494        I: Iterator<Item = (K, &'a U256)>,
495        K: AsRef<[u8]> + Ord,
496    {
497        let hashed = iter
498            .map(|(k, v)| (keccak256(k.as_ref()), alloy_rlp::encode(v).to_vec()))
499            // Collect into a btree map to sort the data
500            .collect::<BTreeMap<_, _>>();
501
502        let mut hb = HashBuilder::default();
503
504        hashed.iter().for_each(|(key, val)| {
505            let nibbles = Nibbles::unpack(key);
506            hb.add_leaf(nibbles, val);
507        });
508
509        assert_eq!(hb.root(), triehash_trie_root(&hashed));
510    }
511
512    // No hashing involved
513    fn assert_trie_root<I, K, V>(iter: I)
514    where
515        I: IntoIterator<Item = (K, V)>,
516        K: AsRef<[u8]> + Ord,
517        V: AsRef<[u8]>,
518    {
519        let mut hb = HashBuilder::default();
520
521        let data = iter.into_iter().collect::<BTreeMap<_, _>>();
522        data.iter().for_each(|(key, val)| {
523            let nibbles = Nibbles::unpack(key.as_ref());
524            hb.add_leaf(nibbles, val.as_ref());
525        });
526
527        assert_eq!(hb.root(), triehash_trie_root(data));
528    }
529
530    #[test]
531    fn empty() {
532        assert_eq!(HashBuilder::default().root(), EMPTY_ROOT_HASH);
533    }
534
535    #[test]
536    #[cfg(feature = "arbitrary")]
537    #[cfg_attr(miri, ignore = "no proptest")]
538    fn arbitrary_hashed_root() {
539        use proptest::prelude::*;
540        proptest!(|(state: BTreeMap<B256, U256>)| {
541            assert_hashed_trie_root(state.iter());
542        });
543    }
544
545    #[test]
546    fn test_generates_branch_node() {
547        let mut hb = HashBuilder::default().with_updates(true);
548
549        // We have 1 branch node update to be stored at 0x01, indicated by the first nibble.
550        // That branch root node has 4 children:
551        // - Leaf at nibble `0`: It has an empty value.
552        // - Branch at nibble `1`: It has 2 leaf nodes with empty values at nibbles `0` and `1`.
553        // - Branch at nibble `2`: It has 2 leaf nodes with empty values at nibbles `0` and `2`.
554        // - Leaf at nibble `3`: It has an empty value.
555        //
556        // This is enough information to construct the intermediate node value:
557        // 1. State Mask: 0b1111. All children of the branch node set at nibbles `0`, `1`, `2` and
558        //    `3`.
559        // 2. Hash Mask: 0b0110. Of the above items, nibbles `1` and `2` correspond to children that
560        //    are branch nodes.
561        // 3. Tree Mask: 0b0000. None of the children are stored in the database (yet).
562        // 4. Hashes: Hashes of the 2 sub-branch roots, at nibbles `1` and `2`. Calculated by
563        //    hashing the 0th and 1st element for the branch at nibble `1` , and the 0th and 2nd
564        //    element for the branch at nibble `2`. This basically means that every
565        //    BranchNodeCompact is capable of storing up to 2 levels deep of nodes (?).
566        let data = BTreeMap::from([
567            (
568                // Leaf located at nibble `0` of the branch root node that doesn't result in
569                // creating another branch node
570                hex!("1000000000000000000000000000000000000000000000000000000000000000").to_vec(),
571                Vec::new(),
572            ),
573            (
574                hex!("1100000000000000000000000000000000000000000000000000000000000000").to_vec(),
575                Vec::new(),
576            ),
577            (
578                hex!("1110000000000000000000000000000000000000000000000000000000000000").to_vec(),
579                Vec::new(),
580            ),
581            (
582                hex!("1200000000000000000000000000000000000000000000000000000000000000").to_vec(),
583                Vec::new(),
584            ),
585            (
586                hex!("1220000000000000000000000000000000000000000000000000000000000000").to_vec(),
587                Vec::new(),
588            ),
589            (
590                // Leaf located at nibble `3` of the branch root node that doesn't result in
591                // creating another branch node
592                hex!("1320000000000000000000000000000000000000000000000000000000000000").to_vec(),
593                Vec::new(),
594            ),
595        ]);
596        data.iter().for_each(|(key, val)| {
597            let nibbles = Nibbles::unpack(key);
598            hb.add_leaf(nibbles, val.as_ref());
599        });
600        let _root = hb.root();
601
602        let (_, updates) = hb.split();
603
604        let update = updates.get(&Nibbles::from_nibbles_unchecked(hex!("01"))).unwrap();
605        // Nibbles 0, 1, 2, 3 have children
606        assert_eq!(update.state_mask, TrieMask::new(0b1111));
607        // None of the children are stored in the database
608        assert_eq!(update.tree_mask, TrieMask::new(0b0000));
609        // Children under nibbles `1` and `2` are branch nodes with `hashes`
610        assert_eq!(update.hash_mask, TrieMask::new(0b0110));
611        // Calculated when running the hash builder
612        assert_eq!(update.hashes.len(), 2);
613
614        assert_eq!(_root, triehash_trie_root(data));
615    }
616
617    #[test]
618    fn test_root_raw_data() {
619        let data = [
620            (hex!("646f").to_vec(), hex!("76657262").to_vec()),
621            (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()),
622            (hex!("676f6b32").to_vec(), hex!("7075707079").to_vec()),
623            (hex!("676f6b34").to_vec(), hex!("7075707079").to_vec()),
624        ];
625        assert_trie_root(data);
626    }
627
628    #[test]
629    fn test_root_rlp_hashed_data() {
630        let data: HashMap<_, _, _> = HashMap::from([
631            (B256::with_last_byte(1), U256::from(2)),
632            (B256::with_last_byte(3), U256::from(4)),
633        ]);
634        assert_hashed_trie_root(data.iter());
635    }
636
637    #[test]
638    fn test_root_known_hash() {
639        let root_hash = b256!("45596e474b536a6b4d64764e4f75514d544577646c414e684271706871446456");
640        let mut hb = HashBuilder::default();
641        hb.add_branch(Nibbles::default(), root_hash, false);
642        assert_eq!(hb.root(), root_hash);
643    }
644
645    #[test]
646    fn manual_branch_node_ok() {
647        let raw_input = vec![
648            (hex!("646f").to_vec(), hex!("76657262").to_vec()),
649            (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()),
650        ];
651        let expected = triehash_trie_root(raw_input.clone());
652
653        // We create the hash builder and add the leaves
654        let mut hb = HashBuilder::default();
655        for (key, val) in &raw_input {
656            hb.add_leaf(Nibbles::unpack(key), val);
657        }
658
659        // Manually create the branch node that should be there after the first 2 leaves are added.
660        // Skip the 0th element given in this example they have a common prefix and will
661        // collapse to a Branch node.
662        let leaf1 = LeafNode::new(Nibbles::unpack(&raw_input[0].0[1..]), raw_input[0].1.clone());
663        let leaf2 = LeafNode::new(Nibbles::unpack(&raw_input[1].0[1..]), raw_input[1].1.clone());
664        let mut branch: [&dyn Encodable; 17] = [b""; 17];
665        // We set this to `4` and `7` because that matches the 2nd element of the corresponding
666        // leaves. We set this to `7` because the 2nd element of Leaf 1 is `7`.
667        branch[4] = &leaf1;
668        branch[7] = &leaf2;
669        let mut branch_node_rlp = Vec::new();
670        alloy_rlp::encode_list::<_, dyn Encodable>(&branch, &mut branch_node_rlp);
671        let branch_node_hash = keccak256(branch_node_rlp);
672
673        let mut hb2 = HashBuilder::default();
674        // Insert the branch with the `0x6` shared prefix.
675        hb2.add_branch(Nibbles::from_nibbles_unchecked([0x6]), branch_node_hash, false);
676
677        assert_eq!(hb.root(), expected);
678        assert_eq!(hb2.root(), expected);
679    }
680}