reth_trie_sparse/
trie.rs

1use crate::{
2    provider::{RevealedNode, TrieNodeProvider},
3    LeafLookup, LeafLookupError, SparseTrieInterface, SparseTrieUpdates,
4};
5use alloc::{
6    borrow::Cow,
7    boxed::Box,
8    fmt,
9    string::{String, ToString},
10    vec,
11    vec::Vec,
12};
13use alloy_primitives::{
14    hex, keccak256,
15    map::{Entry, HashMap, HashSet},
16    B256,
17};
18use alloy_rlp::Decodable;
19use reth_execution_errors::{SparseTrieErrorKind, SparseTrieResult};
20use reth_trie_common::{
21    prefix_set::{PrefixSet, PrefixSetMut},
22    BranchNodeCompact, BranchNodeMasks, BranchNodeMasksMap, BranchNodeRef, ExtensionNodeRef,
23    LeafNodeRef, Nibbles, ProofTrieNode, RlpNode, TrieMask, TrieMasks, TrieNode, CHILD_INDEX_RANGE,
24    EMPTY_ROOT_HASH,
25};
26use smallvec::SmallVec;
27use tracing::{debug, instrument, trace};
28
29/// The level below which the sparse trie hashes are calculated in
30/// [`SerialSparseTrie::update_subtrie_hashes`].
31const SPARSE_TRIE_SUBTRIE_HASHES_LEVEL: usize = 2;
32
33/// A sparse trie that is either in a "blind" state (no nodes are revealed, root node hash is
34/// unknown) or in a "revealed" state (root node has been revealed and the trie can be updated).
35///
36/// In blind mode the trie does not contain any decoded node data, which saves memory but
37/// prevents direct access to node contents. The revealed mode stores decoded nodes along
38/// with additional information such as values, allowing direct manipulation.
39///
40/// The sparse trie design is optimised for:
41/// 1. Memory efficiency - only revealed nodes are loaded into memory
42/// 2. Update tracking - changes to the trie structure can be tracked and selectively persisted
43/// 3. Incremental operations - nodes can be revealed as needed without loading the entire trie.
44///    This is what gives rise to the notion of a "sparse" trie.
45#[derive(PartialEq, Eq, Debug, Clone)]
46pub enum SparseTrie<T = SerialSparseTrie> {
47    /// The trie is blind -- no nodes have been revealed
48    ///
49    /// This is the default state. In this state, the trie cannot be directly queried or modified
50    /// until nodes are revealed.
51    ///
52    /// In this state the `SparseTrie` can optionally carry with it a cleared `SerialSparseTrie`.
53    /// This allows for reusing the trie's allocations between payload executions.
54    Blind(Option<Box<T>>),
55    /// Some nodes in the Trie have been revealed.
56    ///
57    /// In this state, the trie can be queried and modified for the parts
58    /// that have been revealed. Other parts remain blind and require revealing
59    /// before they can be accessed.
60    Revealed(Box<T>),
61}
62
63impl<T: Default> Default for SparseTrie<T> {
64    fn default() -> Self {
65        Self::Blind(None)
66    }
67}
68
69impl<T: SparseTrieInterface + Default> SparseTrie<T> {
70    /// Creates a new revealed but empty sparse trie with `SparseNode::Empty` as root node.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use reth_trie_sparse::{provider::DefaultTrieNodeProvider, SerialSparseTrie, SparseTrie};
76    ///
77    /// let trie = SparseTrie::<SerialSparseTrie>::revealed_empty();
78    /// assert!(!trie.is_blind());
79    /// ```
80    pub fn revealed_empty() -> Self {
81        Self::Revealed(Box::default())
82    }
83
84    /// Reveals the root node, converting a blind trie into a revealed one.
85    ///
86    /// If the trie is blinded, its root node is replaced with `root`.
87    ///
88    /// The `masks` are used to determine how the node's children are stored.
89    /// The `retain_updates` flag controls whether changes to the trie structure
90    /// should be tracked.
91    ///
92    /// # Returns
93    ///
94    /// A mutable reference to the underlying [`SparseTrieInterface`].
95    pub fn reveal_root(
96        &mut self,
97        root: TrieNode,
98        masks: TrieMasks,
99        retain_updates: bool,
100    ) -> SparseTrieResult<&mut T> {
101        // if `Blind`, we initialize the revealed trie with the given root node, using a
102        // pre-allocated trie if available.
103        if self.is_blind() {
104            let mut revealed_trie = if let Self::Blind(Some(cleared_trie)) = core::mem::take(self) {
105                cleared_trie
106            } else {
107                Box::default()
108            };
109
110            *revealed_trie = revealed_trie.with_root(root, masks, retain_updates)?;
111            *self = Self::Revealed(revealed_trie);
112        }
113
114        Ok(self.as_revealed_mut().unwrap())
115    }
116}
117
118impl<T: SparseTrieInterface> SparseTrie<T> {
119    /// Creates a new blind sparse trie.
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use reth_trie_sparse::{provider::DefaultTrieNodeProvider, SerialSparseTrie, SparseTrie};
125    ///
126    /// let trie = SparseTrie::<SerialSparseTrie>::blind();
127    /// assert!(trie.is_blind());
128    /// let trie = SparseTrie::<SerialSparseTrie>::default();
129    /// assert!(trie.is_blind());
130    /// ```
131    pub const fn blind() -> Self {
132        Self::Blind(None)
133    }
134
135    /// Creates a new blind sparse trie, clearing and later reusing the given
136    /// [`SparseTrieInterface`].
137    pub fn blind_from(mut trie: T) -> Self {
138        trie.clear();
139        Self::Blind(Some(Box::new(trie)))
140    }
141
142    /// Returns `true` if the sparse trie has no revealed nodes.
143    pub const fn is_blind(&self) -> bool {
144        matches!(self, Self::Blind(_))
145    }
146
147    /// Returns `true` if the sparse trie is revealed.
148    pub const fn is_revealed(&self) -> bool {
149        matches!(self, Self::Revealed(_))
150    }
151
152    /// Returns an immutable reference to the underlying revealed sparse trie.
153    ///
154    /// Returns `None` if the trie is blinded.
155    pub const fn as_revealed_ref(&self) -> Option<&T> {
156        if let Self::Revealed(revealed) = self {
157            Some(revealed)
158        } else {
159            None
160        }
161    }
162
163    /// Returns a mutable reference to the underlying revealed sparse trie.
164    ///
165    /// Returns `None` if the trie is blinded.
166    pub fn as_revealed_mut(&mut self) -> Option<&mut T> {
167        if let Self::Revealed(revealed) = self {
168            Some(revealed)
169        } else {
170            None
171        }
172    }
173
174    /// Wipes the trie by removing all nodes and values,
175    /// and resetting the trie to only contain an empty root node.
176    ///
177    /// Note: This method will error if the trie is blinded.
178    pub fn wipe(&mut self) -> SparseTrieResult<()> {
179        let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
180        revealed.wipe();
181        Ok(())
182    }
183
184    /// Calculates the root hash of the trie.
185    ///
186    /// This will update any remaining dirty nodes before computing the root hash.
187    /// "dirty" nodes are nodes that need their hashes to be recomputed because one or more of their
188    /// children's hashes have changed.
189    ///
190    /// # Returns
191    ///
192    /// - `Some(B256)` with the calculated root hash if the trie is revealed.
193    /// - `None` if the trie is still blind.
194    pub fn root(&mut self) -> Option<B256> {
195        Some(self.as_revealed_mut()?.root())
196    }
197
198    /// Returns the root hash along with any accumulated update information.
199    ///
200    /// This is useful for when you need both the root hash and information about
201    /// what nodes were modified, which can be used to efficiently update
202    /// an external database.
203    ///
204    /// # Returns
205    ///
206    /// An `Option` tuple consisting of:
207    ///  - The trie root hash (`B256`).
208    ///  - A [`SparseTrieUpdates`] structure containing information about updated nodes.
209    ///  - `None` if the trie is still blind.
210    pub fn root_with_updates(&mut self) -> Option<(B256, SparseTrieUpdates)> {
211        let revealed = self.as_revealed_mut()?;
212        Some((revealed.root(), revealed.take_updates()))
213    }
214
215    /// Returns a [`SparseTrie::Blind`] based on this one. If this instance was revealed, or was
216    /// itself a `Blind` with a pre-allocated [`SparseTrieInterface`], this will return
217    /// a `Blind` carrying a cleared pre-allocated [`SparseTrieInterface`].
218    pub fn clear(self) -> Self {
219        match self {
220            Self::Blind(_) => self,
221            Self::Revealed(mut trie) => {
222                trie.clear();
223                Self::Blind(Some(trie))
224            }
225        }
226    }
227
228    /// Updates (or inserts) a leaf at the given key path with the specified RLP-encoded value.
229    ///
230    /// # Errors
231    ///
232    /// Returns an error if the trie is still blind, or if the update fails.
233    #[instrument(level = "trace", target = "trie::sparse", skip_all)]
234    pub fn update_leaf(
235        &mut self,
236        path: Nibbles,
237        value: Vec<u8>,
238        provider: impl TrieNodeProvider,
239    ) -> SparseTrieResult<()> {
240        let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
241        revealed.update_leaf(path, value, provider)?;
242        Ok(())
243    }
244
245    /// Removes a leaf node at the specified key path.
246    ///
247    /// # Errors
248    ///
249    /// Returns an error if the trie is still blind, or if the leaf cannot be removed
250    #[instrument(level = "trace", target = "trie::sparse", skip_all)]
251    pub fn remove_leaf(
252        &mut self,
253        path: &Nibbles,
254        provider: impl TrieNodeProvider,
255    ) -> SparseTrieResult<()> {
256        let revealed = self.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?;
257        revealed.remove_leaf(path, provider)?;
258        Ok(())
259    }
260
261    /// Shrinks the capacity of the sparse trie's node storage.
262    /// Works for both revealed and blind tries with allocated storage.
263    pub fn shrink_nodes_to(&mut self, size: usize) {
264        match self {
265            Self::Blind(Some(trie)) | Self::Revealed(trie) => {
266                trie.shrink_nodes_to(size);
267            }
268            _ => {}
269        }
270    }
271
272    /// Shrinks the capacity of the sparse trie's value storage.
273    /// Works for both revealed and blind tries with allocated storage.
274    pub fn shrink_values_to(&mut self, size: usize) {
275        match self {
276            Self::Blind(Some(trie)) | Self::Revealed(trie) => {
277                trie.shrink_values_to(size);
278            }
279            _ => {}
280        }
281    }
282}
283
284/// The representation of revealed sparse trie.
285///
286/// The revealed sparse trie contains the actual trie structure with nodes, values, and
287/// tracking for changes. It supports operations like inserting, updating, and removing
288/// nodes.
289///
290///
291/// ## Invariants
292///
293/// - The root node is always present in `nodes` collection.
294/// - Each leaf entry in `nodes` collection must have a corresponding entry in `values` collection.
295///   The opposite is also true.
296/// - All keys in `values` collection are full leaf paths.
297#[derive(Clone, PartialEq, Eq)]
298pub struct SerialSparseTrie {
299    /// Map from a path (nibbles) to its corresponding sparse trie node.
300    /// This contains all of the revealed nodes in trie.
301    nodes: HashMap<Nibbles, SparseNode>,
302    /// Branch node masks containing `tree_mask` and `hash_mask` for each path.
303    /// - `tree_mask`: When a bit is set, the corresponding child subtree is stored in the
304    ///   database.
305    /// - `hash_mask`: When a bit is set, the corresponding child is stored as a hash in the
306    ///   database.
307    branch_node_masks: BranchNodeMasksMap,
308    /// Map from leaf key paths to their values.
309    /// All values are stored here instead of directly in leaf nodes.
310    values: HashMap<Nibbles, Vec<u8>>,
311    /// Set of prefixes (key paths) that have been marked as updated.
312    /// This is used to track which parts of the trie need to be recalculated.
313    prefix_set: PrefixSetMut,
314    /// Optional tracking of trie updates for later use.
315    updates: Option<SparseTrieUpdates>,
316    /// Reusable buffer for RLP encoding of nodes.
317    rlp_buf: Vec<u8>,
318}
319
320impl fmt::Debug for SerialSparseTrie {
321    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322        f.debug_struct("SerialSparseTrie")
323            .field("nodes", &self.nodes)
324            .field("branch_node_masks", &self.branch_node_masks)
325            .field("values", &self.values)
326            .field("prefix_set", &self.prefix_set)
327            .field("updates", &self.updates)
328            .field("rlp_buf", &hex::encode(&self.rlp_buf))
329            .finish_non_exhaustive()
330    }
331}
332
333/// Turns a [`Nibbles`] into a [`String`] by concatenating each nibbles' hex character.
334fn encode_nibbles(nibbles: &Nibbles) -> String {
335    let encoded = hex::encode(nibbles.pack());
336    encoded[..nibbles.len()].to_string()
337}
338
339impl fmt::Display for SerialSparseTrie {
340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341        // This prints the trie in preorder traversal, using a stack
342        let mut stack = Vec::new();
343        let mut visited = HashSet::new();
344
345        // 4 spaces as indent per level
346        const INDENT: &str = "    ";
347
348        // Track both path and depth
349        stack.push((Nibbles::default(), self.nodes_ref().get(&Nibbles::default()).unwrap(), 0));
350
351        while let Some((path, node, depth)) = stack.pop() {
352            if !visited.insert(path) {
353                continue;
354            }
355
356            // Add indentation if alternate flag (#) is set
357            if f.alternate() {
358                write!(f, "{}", INDENT.repeat(depth))?;
359            }
360
361            let packed_path = if depth == 0 { String::from("Root") } else { encode_nibbles(&path) };
362
363            match node {
364                SparseNode::Empty | SparseNode::Hash(_) => {
365                    writeln!(f, "{packed_path} -> {node:?}")?;
366                }
367                SparseNode::Leaf { key, .. } => {
368                    // we want to append the key to the path
369                    let mut full_path = path;
370                    full_path.extend(key);
371                    let packed_path = encode_nibbles(&full_path);
372
373                    writeln!(f, "{packed_path} -> {node:?}")?;
374                }
375                SparseNode::Extension { key, .. } => {
376                    writeln!(f, "{packed_path} -> {node:?}")?;
377
378                    // push the child node onto the stack with increased depth
379                    let mut child_path = path;
380                    child_path.extend(key);
381                    if let Some(child_node) = self.nodes_ref().get(&child_path) {
382                        stack.push((child_path, child_node, depth + 1));
383                    }
384                }
385                SparseNode::Branch { state_mask, .. } => {
386                    writeln!(f, "{packed_path} -> {node:?}")?;
387
388                    for i in CHILD_INDEX_RANGE.rev() {
389                        if state_mask.is_bit_set(i) {
390                            let mut child_path = path;
391                            child_path.push_unchecked(i);
392                            if let Some(child_node) = self.nodes_ref().get(&child_path) {
393                                stack.push((child_path, child_node, depth + 1));
394                            }
395                        }
396                    }
397                }
398            }
399        }
400
401        Ok(())
402    }
403}
404
405impl Default for SerialSparseTrie {
406    fn default() -> Self {
407        Self {
408            nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]),
409            branch_node_masks: BranchNodeMasksMap::default(),
410            values: HashMap::default(),
411            prefix_set: PrefixSetMut::default(),
412            updates: None,
413            rlp_buf: Vec::new(),
414        }
415    }
416}
417
418impl SparseTrieInterface for SerialSparseTrie {
419    fn with_root(
420        mut self,
421        root: TrieNode,
422        masks: TrieMasks,
423        retain_updates: bool,
424    ) -> SparseTrieResult<Self> {
425        self = self.with_updates(retain_updates);
426
427        // A fresh/cleared `SerialSparseTrie` has a `SparseNode::Empty` at its root. Delete that
428        // so we can reveal the new root node.
429        let path = Nibbles::default();
430        let _removed_root = self.nodes.remove(&path).expect("root node should exist");
431        debug_assert_eq!(_removed_root, SparseNode::Empty);
432
433        self.reveal_node(path, root, masks)?;
434        Ok(self)
435    }
436
437    fn with_updates(mut self, retain_updates: bool) -> Self {
438        if retain_updates {
439            self.updates = Some(SparseTrieUpdates::default());
440        }
441        self
442    }
443
444    fn reserve_nodes(&mut self, additional: usize) {
445        self.nodes.reserve(additional);
446    }
447    fn reveal_node(
448        &mut self,
449        path: Nibbles,
450        node: TrieNode,
451        masks: TrieMasks,
452    ) -> SparseTrieResult<()> {
453        trace!(target: "trie::sparse", ?path, ?node, ?masks, "reveal_node called");
454
455        // If the node is already revealed and it's not a hash node, do nothing.
456        if self.nodes.get(&path).is_some_and(|node| !node.is_hash()) {
457            return Ok(())
458        }
459
460        if masks.tree_mask.is_some() || masks.hash_mask.is_some() {
461            self.branch_node_masks.insert(
462                path,
463                BranchNodeMasks {
464                    tree_mask: masks.tree_mask.unwrap_or_default(),
465                    hash_mask: masks.hash_mask.unwrap_or_default(),
466                },
467            );
468        }
469
470        match node {
471            TrieNode::EmptyRoot => {
472                // For an empty root, ensure that we are at the root path.
473                debug_assert!(path.is_empty());
474                self.nodes.insert(path, SparseNode::Empty);
475            }
476            TrieNode::Branch(branch) => {
477                // For a branch node, iterate over all potential children
478                let mut stack_ptr = branch.as_ref().first_child_index();
479                for idx in CHILD_INDEX_RANGE {
480                    if branch.state_mask.is_bit_set(idx) {
481                        let mut child_path = path;
482                        child_path.push_unchecked(idx);
483                        // Reveal each child node or hash it has
484                        self.reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?;
485                        stack_ptr += 1;
486                    }
487                }
488                // Update the branch node entry in the nodes map, handling cases where a blinded
489                // node is now replaced with a revealed node.
490                match self.nodes.entry(path) {
491                    Entry::Occupied(mut entry) => match entry.get() {
492                        // Replace a hash node with a fully revealed branch node.
493                        SparseNode::Hash(hash) => {
494                            entry.insert(SparseNode::Branch {
495                                state_mask: branch.state_mask,
496                                // Memoize the hash of a previously blinded node in a new branch
497                                // node.
498                                hash: Some(*hash),
499                                store_in_db_trie: Some(
500                                    masks.hash_mask.is_some_and(|mask| !mask.is_empty()) ||
501                                        masks.tree_mask.is_some_and(|mask| !mask.is_empty()),
502                                ),
503                            });
504                        }
505                        // Branch node already exists, or an extension node was placed where a
506                        // branch node was before.
507                        SparseNode::Branch { .. } | SparseNode::Extension { .. } => {}
508                        // All other node types can't be handled.
509                        node @ (SparseNode::Empty | SparseNode::Leaf { .. }) => {
510                            return Err(SparseTrieErrorKind::Reveal {
511                                path: *entry.key(),
512                                node: Box::new(node.clone()),
513                            }
514                            .into())
515                        }
516                    },
517                    Entry::Vacant(entry) => {
518                        entry.insert(SparseNode::new_branch(branch.state_mask));
519                    }
520                }
521            }
522            TrieNode::Extension(ext) => match self.nodes.entry(path) {
523                Entry::Occupied(mut entry) => match entry.get() {
524                    // Replace a hash node with a revealed extension node.
525                    SparseNode::Hash(hash) => {
526                        let mut child_path = *entry.key();
527                        child_path.extend(&ext.key);
528                        entry.insert(SparseNode::Extension {
529                            key: ext.key,
530                            // Memoize the hash of a previously blinded node in a new extension
531                            // node.
532                            hash: Some(*hash),
533                            store_in_db_trie: None,
534                        });
535                        self.reveal_node_or_hash(child_path, &ext.child)?;
536                    }
537                    // Extension node already exists, or an extension node was placed where a branch
538                    // node was before.
539                    SparseNode::Extension { .. } | SparseNode::Branch { .. } => {}
540                    // All other node types can't be handled.
541                    node @ (SparseNode::Empty | SparseNode::Leaf { .. }) => {
542                        return Err(SparseTrieErrorKind::Reveal {
543                            path: *entry.key(),
544                            node: Box::new(node.clone()),
545                        }
546                        .into())
547                    }
548                },
549                Entry::Vacant(entry) => {
550                    let mut child_path = *entry.key();
551                    child_path.extend(&ext.key);
552                    entry.insert(SparseNode::new_ext(ext.key));
553                    self.reveal_node_or_hash(child_path, &ext.child)?;
554                }
555            },
556            TrieNode::Leaf(leaf) => match self.nodes.entry(path) {
557                Entry::Occupied(mut entry) => match entry.get() {
558                    // Replace a hash node with a revealed leaf node and store leaf node value.
559                    SparseNode::Hash(hash) => {
560                        let mut full = *entry.key();
561                        full.extend(&leaf.key);
562                        self.values.insert(full, leaf.value.clone());
563                        entry.insert(SparseNode::Leaf {
564                            key: leaf.key,
565                            // Memoize the hash of a previously blinded node in a new leaf
566                            // node.
567                            hash: Some(*hash),
568                        });
569                    }
570                    // Left node already exists.
571                    SparseNode::Leaf { .. } => {}
572                    // All other node types can't be handled.
573                    node @ (SparseNode::Empty |
574                    SparseNode::Extension { .. } |
575                    SparseNode::Branch { .. }) => {
576                        return Err(SparseTrieErrorKind::Reveal {
577                            path: *entry.key(),
578                            node: Box::new(node.clone()),
579                        }
580                        .into())
581                    }
582                },
583                Entry::Vacant(entry) => {
584                    let mut full = *entry.key();
585                    full.extend(&leaf.key);
586                    entry.insert(SparseNode::new_leaf(leaf.key));
587                    self.values.insert(full, leaf.value.clone());
588                }
589            },
590        }
591
592        Ok(())
593    }
594
595    fn reveal_nodes(&mut self, mut nodes: Vec<ProofTrieNode>) -> SparseTrieResult<()> {
596        nodes.sort_unstable_by_key(|node| node.path);
597        for node in nodes {
598            self.reveal_node(node.path, node.node, node.masks)?;
599        }
600        Ok(())
601    }
602
603    #[instrument(level = "trace", target = "trie::sparse::serial", skip(self, provider))]
604    fn update_leaf<P: TrieNodeProvider>(
605        &mut self,
606        full_path: Nibbles,
607        value: Vec<u8>,
608        provider: P,
609    ) -> SparseTrieResult<()> {
610        self.prefix_set.insert(full_path);
611        let existing = self.values.insert(full_path, value);
612        if existing.is_some() {
613            // trie structure unchanged, return immediately
614            return Ok(())
615        }
616
617        let mut current = Nibbles::default();
618        while let Some(node) = self.nodes.get_mut(&current) {
619            match node {
620                SparseNode::Empty => {
621                    *node = SparseNode::new_leaf(full_path);
622                    break
623                }
624                &mut SparseNode::Hash(hash) => {
625                    return Err(SparseTrieErrorKind::BlindedNode { path: current, hash }.into())
626                }
627                SparseNode::Leaf { key: current_key, .. } => {
628                    current.extend(current_key);
629
630                    // this leaf is being updated
631                    if current == full_path {
632                        unreachable!("we already checked leaf presence in the beginning");
633                    }
634
635                    // find the common prefix
636                    let common = current.common_prefix_length(&full_path);
637
638                    // update existing node
639                    let new_ext_key = current.slice(current.len() - current_key.len()..common);
640                    *node = SparseNode::new_ext(new_ext_key);
641
642                    // create a branch node and corresponding leaves
643                    self.nodes.reserve(3);
644                    self.nodes.insert(
645                        current.slice(..common),
646                        SparseNode::new_split_branch(
647                            current.get_unchecked(common),
648                            full_path.get_unchecked(common),
649                        ),
650                    );
651                    self.nodes.insert(
652                        full_path.slice(..=common),
653                        SparseNode::new_leaf(full_path.slice(common + 1..)),
654                    );
655                    self.nodes.insert(
656                        current.slice(..=common),
657                        SparseNode::new_leaf(current.slice(common + 1..)),
658                    );
659
660                    break;
661                }
662                SparseNode::Extension { key, .. } => {
663                    current.extend(key);
664
665                    if !full_path.starts_with(&current) {
666                        // find the common prefix
667                        let common = current.common_prefix_length(&full_path);
668                        *key = current.slice(current.len() - key.len()..common);
669
670                        // If branch node updates retention is enabled, we need to query the
671                        // extension node child to later set the hash mask for a parent branch node
672                        // correctly.
673                        if self.updates.is_some() {
674                            // Check if the extension node child is a hash that needs to be revealed
675                            if self.nodes.get(&current).unwrap().is_hash() {
676                                debug!(
677                                    target: "trie::sparse",
678                                    leaf_full_path = ?full_path,
679                                    child_path = ?current,
680                                    "Extension node child not revealed in update_leaf, falling back to db",
681                                );
682                                if let Some(RevealedNode { node, tree_mask, hash_mask }) =
683                                    provider.trie_node(&current)?
684                                {
685                                    let decoded = TrieNode::decode(&mut &node[..])?;
686                                    trace!(
687                                        target: "trie::sparse",
688                                        ?current,
689                                        ?decoded,
690                                        ?tree_mask,
691                                        ?hash_mask,
692                                        "Revealing extension node child",
693                                    );
694                                    self.reveal_node(
695                                        current,
696                                        decoded,
697                                        TrieMasks { hash_mask, tree_mask },
698                                    )?;
699                                }
700                            }
701                        }
702
703                        // create state mask for new branch node
704                        // NOTE: this might overwrite the current extension node
705                        self.nodes.reserve(3);
706                        let branch = SparseNode::new_split_branch(
707                            current.get_unchecked(common),
708                            full_path.get_unchecked(common),
709                        );
710                        self.nodes.insert(current.slice(..common), branch);
711
712                        // create new leaf
713                        let new_leaf = SparseNode::new_leaf(full_path.slice(common + 1..));
714                        self.nodes.insert(full_path.slice(..=common), new_leaf);
715
716                        // recreate extension to previous child if needed
717                        let key = current.slice(common + 1..);
718                        if !key.is_empty() {
719                            self.nodes.insert(current.slice(..=common), SparseNode::new_ext(key));
720                        }
721
722                        break;
723                    }
724                }
725                SparseNode::Branch { state_mask, .. } => {
726                    let nibble = full_path.get_unchecked(current.len());
727                    current.push_unchecked(nibble);
728                    if !state_mask.is_bit_set(nibble) {
729                        state_mask.set_bit(nibble);
730                        let new_leaf = SparseNode::new_leaf(full_path.slice(current.len()..));
731                        self.nodes.insert(current, new_leaf);
732                        break;
733                    }
734                }
735            };
736        }
737
738        Ok(())
739    }
740
741    #[instrument(level = "trace", target = "trie::sparse::serial", skip(self, provider))]
742    fn remove_leaf<P: TrieNodeProvider>(
743        &mut self,
744        full_path: &Nibbles,
745        provider: P,
746    ) -> SparseTrieResult<()> {
747        trace!(target: "trie::sparse", ?full_path, "remove_leaf called");
748
749        if self.values.remove(full_path).is_none() {
750            if let Some(&SparseNode::Hash(hash)) = self.nodes.get(full_path) {
751                // Leaf is present in the trie, but it's blinded.
752                return Err(SparseTrieErrorKind::BlindedNode { path: *full_path, hash }.into())
753            }
754
755            trace!(target: "trie::sparse", ?full_path, "Leaf node is not present in the trie");
756            // Leaf is not present in the trie.
757            return Ok(())
758        }
759        self.prefix_set.insert(*full_path);
760
761        // If the path wasn't present in `values`, we still need to walk the trie and ensure that
762        // there is no node at the path. When a leaf node is a blinded `Hash`, it will have an entry
763        // in `nodes`, but not in the `values`.
764
765        let mut removed_nodes = self.take_nodes_for_path(full_path)?;
766        // Pop the first node from the stack which is the leaf node we want to remove.
767        let mut child = removed_nodes.pop().expect("leaf exists");
768        #[cfg(debug_assertions)]
769        {
770            let mut child_path = child.path;
771            let SparseNode::Leaf { key, .. } = &child.node else { panic!("expected leaf node") };
772            child_path.extend(key);
773            assert_eq!(&child_path, full_path);
774        }
775
776        // If we don't have any other removed nodes, insert an empty node at the root.
777        if removed_nodes.is_empty() {
778            debug_assert!(self.nodes.is_empty());
779            self.nodes.insert(Nibbles::default(), SparseNode::Empty);
780
781            return Ok(())
782        }
783
784        // Walk the stack of removed nodes from the back and re-insert them back into the trie,
785        // adjusting the node type as needed.
786        while let Some(removed_node) = removed_nodes.pop() {
787            let removed_path = removed_node.path;
788
789            let new_node = match &removed_node.node {
790                SparseNode::Empty => return Err(SparseTrieErrorKind::Blind.into()),
791                &SparseNode::Hash(hash) => {
792                    return Err(SparseTrieErrorKind::BlindedNode { path: removed_path, hash }.into())
793                }
794                SparseNode::Leaf { .. } => {
795                    unreachable!("we already popped the leaf node")
796                }
797                SparseNode::Extension { key, .. } => {
798                    // If the node is an extension node, we need to look at its child to see if we
799                    // need to merge them.
800                    match &child.node {
801                        SparseNode::Empty => return Err(SparseTrieErrorKind::Blind.into()),
802                        &SparseNode::Hash(hash) => {
803                            return Err(
804                                SparseTrieErrorKind::BlindedNode { path: child.path, hash }.into()
805                            )
806                        }
807                        // For a leaf node, we collapse the extension node into a leaf node,
808                        // extending the key. While it's impossible to encounter an extension node
809                        // followed by a leaf node in a complete trie, it's possible here because we
810                        // could have downgraded the extension node's child into a leaf node from
811                        // another node type.
812                        SparseNode::Leaf { key: leaf_key, .. } => {
813                            self.nodes.remove(&child.path);
814
815                            let mut new_key = *key;
816                            new_key.extend(leaf_key);
817                            SparseNode::new_leaf(new_key)
818                        }
819                        // For an extension node, we collapse them into one extension node,
820                        // extending the key
821                        SparseNode::Extension { key: extension_key, .. } => {
822                            self.nodes.remove(&child.path);
823
824                            let mut new_key = *key;
825                            new_key.extend(extension_key);
826                            SparseNode::new_ext(new_key)
827                        }
828                        // For a branch node, we just leave the extension node as-is.
829                        SparseNode::Branch { .. } => removed_node.node,
830                    }
831                }
832                &SparseNode::Branch { mut state_mask, hash: _, store_in_db_trie: _ } => {
833                    // If the node is a branch node, we need to check the number of children left
834                    // after deleting the child at the given nibble.
835
836                    if let Some(removed_nibble) = removed_node.unset_branch_nibble {
837                        state_mask.unset_bit(removed_nibble);
838                    }
839
840                    // If only one child is left set in the branch node, we need to collapse it.
841                    if state_mask.count_bits() == 1 {
842                        let child_nibble =
843                            state_mask.first_set_bit_index().expect("state mask is not empty");
844
845                        // Get full path of the only child node left.
846                        let mut child_path = removed_path;
847                        child_path.push_unchecked(child_nibble);
848
849                        trace!(target: "trie::sparse", ?removed_path, ?child_path, "Branch node has only one child");
850
851                        // If the remaining child node is not yet revealed then we have to reveal
852                        // it here, otherwise it's not possible to know how to collapse the branch.
853                        let child = self.reveal_remaining_child_on_leaf_removal(
854                            &provider,
855                            full_path,
856                            &child_path,
857                            true, // recurse_into_extension
858                        )?;
859
860                        let mut delete_child = false;
861                        let new_node = match &child {
862                            SparseNode::Empty => return Err(SparseTrieErrorKind::Blind.into()),
863                            &SparseNode::Hash(hash) => {
864                                return Err(SparseTrieErrorKind::BlindedNode {
865                                    path: child_path,
866                                    hash,
867                                }
868                                .into())
869                            }
870                            // If the only child is a leaf node, we downgrade the branch node into a
871                            // leaf node, prepending the nibble to the key, and delete the old
872                            // child.
873                            SparseNode::Leaf { key, .. } => {
874                                delete_child = true;
875
876                                let mut new_key = Nibbles::from_nibbles_unchecked([child_nibble]);
877                                new_key.extend(key);
878                                SparseNode::new_leaf(new_key)
879                            }
880                            // If the only child node is an extension node, we downgrade the branch
881                            // node into an even longer extension node, prepending the nibble to the
882                            // key, and delete the old child.
883                            SparseNode::Extension { key, .. } => {
884                                delete_child = true;
885
886                                let mut new_key = Nibbles::from_nibbles_unchecked([child_nibble]);
887                                new_key.extend(key);
888                                SparseNode::new_ext(new_key)
889                            }
890                            // If the only child is a branch node, we downgrade the current branch
891                            // node into a one-nibble extension node.
892                            SparseNode::Branch { .. } => {
893                                SparseNode::new_ext(Nibbles::from_nibbles_unchecked([child_nibble]))
894                            }
895                        };
896
897                        if delete_child {
898                            self.nodes.remove(&child_path);
899                        }
900
901                        if let Some(updates) = self.updates.as_mut() {
902                            updates.updated_nodes.remove(&removed_path);
903                            updates.removed_nodes.insert(removed_path);
904                        }
905
906                        new_node
907                    }
908                    // If more than one child is left set in the branch, we just re-insert it as-is.
909                    else {
910                        SparseNode::new_branch(state_mask)
911                    }
912                }
913            };
914
915            child = RemovedSparseNode {
916                path: removed_path,
917                node: new_node.clone(),
918                unset_branch_nibble: None,
919            };
920            trace!(target: "trie::sparse", ?removed_path, ?new_node, "Re-inserting the node");
921            self.nodes.insert(removed_path, new_node);
922        }
923
924        Ok(())
925    }
926
927    #[instrument(target = "trie::sparse::serial", skip(self))]
928    fn root(&mut self) -> B256 {
929        // Take the current prefix set
930        let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
931        let rlp_node = self.rlp_node_allocate(&mut prefix_set);
932        if let Some(root_hash) = rlp_node.as_hash() {
933            root_hash
934        } else {
935            keccak256(rlp_node)
936        }
937    }
938
939    fn update_subtrie_hashes(&mut self) {
940        self.update_rlp_node_level(SPARSE_TRIE_SUBTRIE_HASHES_LEVEL);
941    }
942
943    fn get_leaf_value(&self, full_path: &Nibbles) -> Option<&Vec<u8>> {
944        self.values.get(full_path)
945    }
946
947    fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates> {
948        self.updates.as_ref().map_or(Cow::Owned(SparseTrieUpdates::default()), Cow::Borrowed)
949    }
950
951    fn take_updates(&mut self) -> SparseTrieUpdates {
952        self.updates.take().unwrap_or_default()
953    }
954
955    fn wipe(&mut self) {
956        self.nodes = HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]);
957        self.values = HashMap::default();
958        self.prefix_set = PrefixSetMut::all();
959        self.updates = self.updates.is_some().then(SparseTrieUpdates::wiped);
960    }
961
962    fn clear(&mut self) {
963        self.nodes.clear();
964        self.nodes.insert(Nibbles::default(), SparseNode::Empty);
965
966        self.branch_node_masks.clear();
967        self.values.clear();
968        self.prefix_set.clear();
969        self.updates = None;
970        self.rlp_buf.clear();
971    }
972
973    fn find_leaf(
974        &self,
975        full_path: &Nibbles,
976        expected_value: Option<&Vec<u8>>,
977    ) -> Result<LeafLookup, LeafLookupError> {
978        // Helper function to check if a value matches the expected value
979        #[inline]
980        fn check_value_match(
981            actual_value: &Vec<u8>,
982            expected_value: Option<&Vec<u8>>,
983            path: &Nibbles,
984        ) -> Result<(), LeafLookupError> {
985            if let Some(expected) = expected_value &&
986                actual_value != expected
987            {
988                return Err(LeafLookupError::ValueMismatch {
989                    path: *path,
990                    expected: Some(expected.clone()),
991                    actual: actual_value.clone(),
992                });
993            }
994            Ok(())
995        }
996
997        let mut current = Nibbles::default(); // Start at the root
998
999        // Inclusion proof
1000        //
1001        // First, do a quick check if the value exists in our values map.
1002        // We assume that if there exists a leaf node, then its value will
1003        // be in the `values` map.
1004        if let Some(actual_value) = self.values.get(full_path) {
1005            // We found the leaf, check if the value matches (if expected value was provided)
1006            check_value_match(actual_value, expected_value, full_path)?;
1007            return Ok(LeafLookup::Exists);
1008        }
1009
1010        // If the value does not exist in the `values` map, then this means that the leaf either:
1011        // - Does not exist in the trie
1012        // - Is missing from the witness
1013        // We traverse the trie to find the location where this leaf would have been, showing
1014        // that it is not in the trie. Or we find a blinded node, showing that the witness is
1015        // not complete.
1016        while current.len() < full_path.len() {
1017            match self.nodes.get(&current) {
1018                Some(SparseNode::Empty) | None => {
1019                    // None implies no node is at the current path (even in the full trie)
1020                    // Empty node means there is a node at this path and it is "Empty"
1021                    return Ok(LeafLookup::NonExistent);
1022                }
1023                Some(&SparseNode::Hash(hash)) => {
1024                    // We hit a blinded node - cannot determine if leaf exists
1025                    return Err(LeafLookupError::BlindedNode { path: current, hash });
1026                }
1027                Some(SparseNode::Leaf { key, .. }) => {
1028                    // We found a leaf node before reaching our target depth
1029                    current.extend(key);
1030                    if &current == full_path {
1031                        // This should have been handled by our initial values map check
1032                        if let Some(value) = self.values.get(full_path) {
1033                            check_value_match(value, expected_value, full_path)?;
1034                            return Ok(LeafLookup::Exists);
1035                        }
1036                    }
1037
1038                    // The leaf node's path doesn't match our target path,
1039                    // providing an exclusion proof
1040                    return Ok(LeafLookup::NonExistent);
1041                }
1042                Some(SparseNode::Extension { key, .. }) => {
1043                    // Temporarily append the extension key to `current`
1044                    let saved_len = current.len();
1045                    current.extend(key);
1046
1047                    if full_path.len() < current.len() || !full_path.starts_with(&current) {
1048                        current.truncate(saved_len); // restore
1049                        return Ok(LeafLookup::NonExistent);
1050                    }
1051                    // Prefix matched, so we keep walking with the longer `current`.
1052                }
1053                Some(SparseNode::Branch { state_mask, .. }) => {
1054                    // Check if branch has a child at the next nibble in our path
1055                    let nibble = full_path.get_unchecked(current.len());
1056                    if !state_mask.is_bit_set(nibble) {
1057                        // No child at this nibble - exclusion proof
1058                        return Ok(LeafLookup::NonExistent);
1059                    }
1060
1061                    // Continue down the branch
1062                    current.push_unchecked(nibble);
1063                }
1064            }
1065        }
1066
1067        // We've traversed to the end of the path and didn't find a leaf
1068        // Check if there's a node exactly at our target path
1069        match self.nodes.get(full_path) {
1070            Some(SparseNode::Leaf { key, .. }) if key.is_empty() => {
1071                // We found a leaf with an empty key (exact match)
1072                // This should be handled by the values map check above
1073                if let Some(value) = self.values.get(full_path) {
1074                    check_value_match(value, expected_value, full_path)?;
1075                    return Ok(LeafLookup::Exists);
1076                }
1077            }
1078            Some(&SparseNode::Hash(hash)) => {
1079                return Err(LeafLookupError::BlindedNode { path: *full_path, hash });
1080            }
1081            _ => {
1082                // No leaf at exactly the target path
1083                return Ok(LeafLookup::NonExistent);
1084            }
1085        }
1086
1087        // If we get here, there's no leaf at the target path
1088        Ok(LeafLookup::NonExistent)
1089    }
1090
1091    fn shrink_nodes_to(&mut self, size: usize) {
1092        self.nodes.shrink_to(size);
1093        self.branch_node_masks.shrink_to(size);
1094    }
1095
1096    fn shrink_values_to(&mut self, size: usize) {
1097        self.values.shrink_to(size);
1098    }
1099}
1100
1101impl SerialSparseTrie {
1102    /// Creates a new revealed sparse trie from the given root node.
1103    ///
1104    /// This function initializes the internal structures and then reveals the root.
1105    /// It is a convenient method to create a trie when you already have the root node available.
1106    ///
1107    /// # Arguments
1108    ///
1109    /// * `root` - The root node of the trie
1110    /// * `masks` - Trie masks for root branch node
1111    /// * `retain_updates` - Whether to track updates
1112    ///
1113    /// # Returns
1114    ///
1115    /// Self if successful, or an error if revealing fails.
1116    pub fn from_root(
1117        root: TrieNode,
1118        masks: TrieMasks,
1119        retain_updates: bool,
1120    ) -> SparseTrieResult<Self> {
1121        Self::default().with_root(root, masks, retain_updates)
1122    }
1123
1124    /// Returns a reference to the current sparse trie updates.
1125    ///
1126    /// If no updates have been made/recorded, returns an empty update set.
1127    pub fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates> {
1128        self.updates.as_ref().map_or(Cow::Owned(SparseTrieUpdates::default()), Cow::Borrowed)
1129    }
1130
1131    /// Returns an immutable reference to all nodes in the sparse trie.
1132    pub const fn nodes_ref(&self) -> &HashMap<Nibbles, SparseNode> {
1133        &self.nodes
1134    }
1135
1136    /// Reveals either a node or its hash placeholder based on the provided child data.
1137    ///
1138    /// When traversing the trie, we often encounter references to child nodes that
1139    /// are either directly embedded or represented by their hash. This method
1140    /// handles both cases:
1141    ///
1142    /// 1. If the child data represents a hash (32+1=33 bytes), store it as a hash node
1143    /// 2. Otherwise, decode the data as a [`TrieNode`] and recursively reveal it using
1144    ///    `reveal_node`
1145    ///
1146    /// # Returns
1147    ///
1148    /// Returns `Ok(())` if successful, or an error if the node cannot be revealed.
1149    ///
1150    /// # Error Handling
1151    ///
1152    /// Will error if there's a conflict between a new hash node and an existing one
1153    /// at the same path
1154    fn reveal_node_or_hash(&mut self, path: Nibbles, child: &[u8]) -> SparseTrieResult<()> {
1155        if child.len() == B256::len_bytes() + 1 {
1156            let hash = B256::from_slice(&child[1..]);
1157            match self.nodes.entry(path) {
1158                Entry::Occupied(entry) => match entry.get() {
1159                    // Hash node with a different hash can't be handled.
1160                    SparseNode::Hash(previous_hash) if previous_hash != &hash => {
1161                        return Err(SparseTrieErrorKind::Reveal {
1162                            path: *entry.key(),
1163                            node: Box::new(SparseNode::Hash(hash)),
1164                        }
1165                        .into())
1166                    }
1167                    _ => {}
1168                },
1169                Entry::Vacant(entry) => {
1170                    entry.insert(SparseNode::Hash(hash));
1171                }
1172            }
1173            return Ok(())
1174        }
1175
1176        self.reveal_node(path, TrieNode::decode(&mut &child[..])?, TrieMasks::none())
1177    }
1178
1179    /// Traverse the trie from the root down to the leaf at the given path,
1180    /// removing and collecting all nodes along that path.
1181    ///
1182    /// This helper function is used during leaf removal to extract the nodes of the trie
1183    /// that will be affected by the deletion. These nodes are then re-inserted and modified
1184    /// as needed (collapsing extension nodes etc) given that the leaf has now been removed.
1185    ///
1186    /// # Returns
1187    ///
1188    /// Returns a vector of [`RemovedSparseNode`] representing the nodes removed during the
1189    /// traversal.
1190    ///
1191    /// # Errors
1192    ///
1193    /// Returns an error if a blinded node or an empty node is encountered unexpectedly,
1194    /// as these prevent proper removal of the leaf.
1195    fn take_nodes_for_path(&mut self, path: &Nibbles) -> SparseTrieResult<Vec<RemovedSparseNode>> {
1196        let mut current = Nibbles::default(); // Start traversal from the root
1197        let mut nodes = Vec::new(); // Collect traversed nodes
1198
1199        while let Some(node) = self.nodes.remove(&current) {
1200            match &node {
1201                SparseNode::Empty => return Err(SparseTrieErrorKind::Blind.into()),
1202                &SparseNode::Hash(hash) => {
1203                    return Err(SparseTrieErrorKind::BlindedNode { path: current, hash }.into())
1204                }
1205                SparseNode::Leaf { key: _key, .. } => {
1206                    // Leaf node is always the one that we're deleting, and no other leaf nodes can
1207                    // be found during traversal.
1208
1209                    #[cfg(debug_assertions)]
1210                    {
1211                        let mut current = current;
1212                        current.extend(_key);
1213                        assert_eq!(&current, path);
1214                    }
1215
1216                    nodes.push(RemovedSparseNode {
1217                        path: current,
1218                        node,
1219                        unset_branch_nibble: None,
1220                    });
1221                    break
1222                }
1223                SparseNode::Extension { key, .. } => {
1224                    #[cfg(debug_assertions)]
1225                    {
1226                        let mut current = current;
1227                        current.extend(key);
1228                        assert!(
1229                            path.starts_with(&current),
1230                            "path: {path:?}, current: {current:?}, key: {key:?}",
1231                        );
1232                    }
1233
1234                    let path = current;
1235                    current.extend(key);
1236                    nodes.push(RemovedSparseNode { path, node, unset_branch_nibble: None });
1237                }
1238                SparseNode::Branch { state_mask, .. } => {
1239                    let nibble = path.get_unchecked(current.len());
1240                    debug_assert!(
1241                        state_mask.is_bit_set(nibble),
1242                        "current: {current:?}, path: {path:?}, nibble: {nibble:?}, state_mask: {state_mask:?}",
1243                    );
1244
1245                    // If the branch node has a child that is a leaf node that we're removing,
1246                    // we need to unset this nibble.
1247                    // Any other branch nodes will not require unsetting the nibble, because
1248                    // deleting one leaf node can not remove the whole path
1249                    // where the branch node is located.
1250                    let mut child_path = current;
1251                    child_path.push_unchecked(nibble);
1252                    let unset_branch_nibble = self
1253                        .nodes
1254                        .get(&child_path)
1255                        .is_some_and(move |node| match node {
1256                            SparseNode::Leaf { key, .. } => {
1257                                // Get full path of the leaf node
1258                                child_path.extend(key);
1259                                &child_path == path
1260                            }
1261                            _ => false,
1262                        })
1263                        .then_some(nibble);
1264
1265                    nodes.push(RemovedSparseNode { path: current, node, unset_branch_nibble });
1266
1267                    current.push_unchecked(nibble);
1268                }
1269            }
1270        }
1271
1272        Ok(nodes)
1273    }
1274
1275    /// Called when a leaf is removed on a branch which has only one other remaining child. That
1276    /// child must be revealed in order to properly collapse the branch.
1277    ///
1278    /// If `recurse_into_extension` is true, and the remaining child is an extension node, then its
1279    /// child will be ensured to be revealed as well.
1280    ///
1281    /// ## Returns
1282    ///
1283    /// The node of the remaining child, whether it was already revealed or not.
1284    fn reveal_remaining_child_on_leaf_removal<P: TrieNodeProvider>(
1285        &mut self,
1286        provider: P,
1287        full_path: &Nibbles, // only needed for logs
1288        remaining_child_path: &Nibbles,
1289        recurse_into_extension: bool,
1290    ) -> SparseTrieResult<SparseNode> {
1291        let remaining_child_node = match self.nodes.get(remaining_child_path).unwrap() {
1292            SparseNode::Hash(_) => {
1293                debug!(
1294                    target: "trie::parallel_sparse",
1295                    child_path = ?remaining_child_path,
1296                    leaf_full_path = ?full_path,
1297                    "Node child not revealed in remove_leaf, falling back to db",
1298                );
1299                if let Some(RevealedNode { node, tree_mask, hash_mask }) =
1300                    provider.trie_node(remaining_child_path)?
1301                {
1302                    let decoded = TrieNode::decode(&mut &node[..])?;
1303                    trace!(
1304                        target: "trie::parallel_sparse",
1305                        ?remaining_child_path,
1306                        ?decoded,
1307                        ?tree_mask,
1308                        ?hash_mask,
1309                        "Revealing remaining blinded branch child"
1310                    );
1311                    self.reveal_node(
1312                        *remaining_child_path,
1313                        decoded,
1314                        TrieMasks { hash_mask, tree_mask },
1315                    )?;
1316                    self.nodes.get(remaining_child_path).unwrap().clone()
1317                } else {
1318                    return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
1319                        path: *remaining_child_path,
1320                    }
1321                    .into())
1322                }
1323            }
1324            node => node.clone(),
1325        };
1326
1327        // If `recurse_into_extension` is true, and the remaining child is an extension node, then
1328        // its child will be ensured to be revealed as well. This is required for generation of
1329        // trie updates; without revealing the grandchild branch it's not always possible to know
1330        // if the tree mask bit should be set for the child extension on its parent branch.
1331        if let SparseNode::Extension { key, .. } = &remaining_child_node &&
1332            recurse_into_extension
1333        {
1334            let mut remaining_grandchild_path = *remaining_child_path;
1335            remaining_grandchild_path.extend(key);
1336
1337            trace!(
1338                target: "trie::parallel_sparse",
1339                remaining_grandchild_path = ?remaining_grandchild_path,
1340                child_path = ?remaining_child_path,
1341                leaf_full_path = ?full_path,
1342                "Revealing child of extension node, which is the last remaining child of the branch"
1343            );
1344
1345            self.reveal_remaining_child_on_leaf_removal(
1346                provider,
1347                full_path,
1348                &remaining_grandchild_path,
1349                false, // recurse_into_extension
1350            )?;
1351        }
1352
1353        Ok(remaining_child_node)
1354    }
1355
1356    /// Recalculates and updates the RLP hashes of nodes deeper than or equal to the specified
1357    /// `depth`.
1358    ///
1359    /// The root node is considered to be at level 0. This method is useful for optimizing
1360    /// hash recalculations after localized changes to the trie structure:
1361    ///
1362    /// This function identifies all nodes that have changed (based on the prefix set) at the given
1363    /// depth and recalculates their RLP representation.
1364    #[instrument(level = "trace", target = "trie::sparse::serial", skip(self))]
1365    pub fn update_rlp_node_level(&mut self, depth: usize) {
1366        // Take the current prefix set
1367        let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
1368        let mut buffers = RlpNodeBuffers::default();
1369
1370        // Get the nodes that have changed at the given depth.
1371        let (targets, new_prefix_set) = self.get_changed_nodes_at_depth(&mut prefix_set, depth);
1372        // Update the prefix set to the prefix set of the nodes that still need to be updated.
1373        self.prefix_set = new_prefix_set;
1374
1375        trace!(target: "trie::sparse", ?depth, ?targets, "Updating nodes at depth");
1376
1377        let mut temp_rlp_buf = core::mem::take(&mut self.rlp_buf);
1378        for (level, path) in targets {
1379            buffers.path_stack.push(RlpNodePathStackItem {
1380                level,
1381                path,
1382                is_in_prefix_set: Some(true),
1383            });
1384            self.rlp_node(&mut prefix_set, &mut buffers, &mut temp_rlp_buf);
1385        }
1386        self.rlp_buf = temp_rlp_buf;
1387    }
1388
1389    /// Returns a list of (level, path) tuples identifying the nodes that have changed at the
1390    /// specified depth, along with a new prefix set for the paths above the provided depth that
1391    /// remain unchanged.
1392    ///
1393    /// Leaf nodes with a depth less than `depth` are returned too.
1394    ///
1395    /// This method helps optimize hash recalculations by identifying which specific
1396    /// nodes need to be updated at each level of the trie.
1397    ///
1398    /// # Parameters
1399    ///
1400    /// - `prefix_set`: The current prefix set tracking which paths need updates.
1401    /// - `depth`: The minimum depth (relative to the root) to include nodes in the targets.
1402    ///
1403    /// # Returns
1404    ///
1405    /// A tuple containing:
1406    /// - A vector of `(level, Nibbles)` pairs for nodes that require updates at or below the
1407    ///   specified depth.
1408    /// - A `PrefixSetMut` containing paths shallower than the specified depth that still need to be
1409    ///   tracked for future updates.
1410    #[instrument(level = "trace", target = "trie::sparse::serial", skip(self))]
1411    fn get_changed_nodes_at_depth(
1412        &self,
1413        prefix_set: &mut PrefixSet,
1414        depth: usize,
1415    ) -> (Vec<(usize, Nibbles)>, PrefixSetMut) {
1416        let mut unchanged_prefix_set = PrefixSetMut::default();
1417        let mut paths = Vec::from([(Nibbles::default(), 0)]);
1418        let mut targets = Vec::new();
1419
1420        while let Some((mut path, level)) = paths.pop() {
1421            match self.nodes.get(&path).unwrap() {
1422                SparseNode::Empty | SparseNode::Hash(_) => {}
1423                SparseNode::Leaf { key: _, hash } => {
1424                    if hash.is_some() && !prefix_set.contains(&path) {
1425                        continue
1426                    }
1427
1428                    targets.push((level, path));
1429                }
1430                SparseNode::Extension { key, hash, store_in_db_trie: _ } => {
1431                    if hash.is_some() && !prefix_set.contains(&path) {
1432                        continue
1433                    }
1434
1435                    if level >= depth {
1436                        targets.push((level, path));
1437                    } else {
1438                        unchanged_prefix_set.insert(path);
1439
1440                        path.extend(key);
1441                        paths.push((path, level + 1));
1442                    }
1443                }
1444                SparseNode::Branch { state_mask, hash, store_in_db_trie: _ } => {
1445                    if hash.is_some() && !prefix_set.contains(&path) {
1446                        continue
1447                    }
1448
1449                    if level >= depth {
1450                        targets.push((level, path));
1451                    } else {
1452                        unchanged_prefix_set.insert(path);
1453
1454                        for bit in CHILD_INDEX_RANGE.rev() {
1455                            if state_mask.is_bit_set(bit) {
1456                                let mut child_path = path;
1457                                child_path.push_unchecked(bit);
1458                                paths.push((child_path, level + 1));
1459                            }
1460                        }
1461                    }
1462                }
1463            }
1464        }
1465
1466        (targets, unchanged_prefix_set)
1467    }
1468
1469    /// Look up or calculate the RLP of the node at the root path.
1470    ///
1471    /// # Panics
1472    ///
1473    /// If the node at provided path does not exist.
1474    pub fn rlp_node_allocate(&mut self, prefix_set: &mut PrefixSet) -> RlpNode {
1475        let mut buffers = RlpNodeBuffers::new_with_root_path();
1476        let mut temp_rlp_buf = core::mem::take(&mut self.rlp_buf);
1477        let result = self.rlp_node(prefix_set, &mut buffers, &mut temp_rlp_buf);
1478        self.rlp_buf = temp_rlp_buf;
1479
1480        result
1481    }
1482
1483    /// Looks up or computes the RLP encoding of the node specified by the current
1484    /// path in the provided buffers.
1485    ///
1486    /// The function uses a stack (`RlpNodeBuffers::path_stack`) to track the traversal and
1487    /// accumulate RLP encodings.
1488    ///
1489    /// # Parameters
1490    ///
1491    /// - `prefix_set`: The set of trie paths that need their nodes updated.
1492    /// - `buffers`: The reusable buffers for stack management and temporary RLP values.
1493    ///
1494    /// # Panics
1495    ///
1496    /// If the node at provided path does not exist.
1497    #[instrument(level = "trace", target = "trie::sparse::serial", skip_all, ret(level = "trace"))]
1498    pub fn rlp_node(
1499        &mut self,
1500        prefix_set: &mut PrefixSet,
1501        buffers: &mut RlpNodeBuffers,
1502        rlp_buf: &mut Vec<u8>,
1503    ) -> RlpNode {
1504        let _starting_path = buffers.path_stack.last().map(|item| item.path);
1505
1506        'main: while let Some(RlpNodePathStackItem { level, path, mut is_in_prefix_set }) =
1507            buffers.path_stack.pop()
1508        {
1509            let node = self.nodes.get_mut(&path).unwrap();
1510            trace!(
1511                target: "trie::sparse",
1512                ?_starting_path,
1513                ?level,
1514                ?path,
1515                ?is_in_prefix_set,
1516                ?node,
1517                "Popped node from path stack"
1518            );
1519
1520            // Check if the path is in the prefix set.
1521            // First, check the cached value. If it's `None`, then check the prefix set, and update
1522            // the cached value.
1523            let mut prefix_set_contains =
1524                |path: &Nibbles| *is_in_prefix_set.get_or_insert_with(|| prefix_set.contains(path));
1525
1526            let (rlp_node, node_type) = match node {
1527                SparseNode::Empty => (RlpNode::word_rlp(&EMPTY_ROOT_HASH), SparseNodeType::Empty),
1528                SparseNode::Hash(hash) => (RlpNode::word_rlp(hash), SparseNodeType::Hash),
1529                SparseNode::Leaf { key, hash } => {
1530                    let mut path = path;
1531                    path.extend(key);
1532                    if let Some(hash) = hash.filter(|_| !prefix_set_contains(&path)) {
1533                        (RlpNode::word_rlp(&hash), SparseNodeType::Leaf)
1534                    } else {
1535                        let value = self.values.get(&path).unwrap();
1536                        rlp_buf.clear();
1537                        let rlp_node = LeafNodeRef { key, value }.rlp(rlp_buf);
1538                        *hash = rlp_node.as_hash();
1539                        (rlp_node, SparseNodeType::Leaf)
1540                    }
1541                }
1542                SparseNode::Extension { key, hash, store_in_db_trie } => {
1543                    let mut child_path = path;
1544                    child_path.extend(key);
1545                    if let Some((hash, store_in_db_trie)) =
1546                        hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
1547                    {
1548                        (
1549                            RlpNode::word_rlp(&hash),
1550                            SparseNodeType::Extension { store_in_db_trie: Some(store_in_db_trie) },
1551                        )
1552                    } else if buffers.rlp_node_stack.last().is_some_and(|e| e.path == child_path) {
1553                        let RlpNodeStackItem {
1554                            path: _,
1555                            rlp_node: child,
1556                            node_type: child_node_type,
1557                        } = buffers.rlp_node_stack.pop().unwrap();
1558                        rlp_buf.clear();
1559                        let rlp_node = ExtensionNodeRef::new(key, &child).rlp(rlp_buf);
1560                        *hash = rlp_node.as_hash();
1561
1562                        let store_in_db_trie_value = child_node_type.store_in_db_trie();
1563
1564                        trace!(
1565                            target: "trie::sparse",
1566                            ?path,
1567                            ?child_path,
1568                            ?child_node_type,
1569                            "Extension node"
1570                        );
1571
1572                        *store_in_db_trie = store_in_db_trie_value;
1573
1574                        (
1575                            rlp_node,
1576                            SparseNodeType::Extension {
1577                                // Inherit the `store_in_db_trie` flag from the child node, which is
1578                                // always the branch node
1579                                store_in_db_trie: store_in_db_trie_value,
1580                            },
1581                        )
1582                    } else {
1583                        // need to get rlp node for child first
1584                        buffers.path_stack.extend([
1585                            RlpNodePathStackItem { level, path, is_in_prefix_set },
1586                            RlpNodePathStackItem {
1587                                level: level + 1,
1588                                path: child_path,
1589                                is_in_prefix_set: None,
1590                            },
1591                        ]);
1592                        continue
1593                    }
1594                }
1595                SparseNode::Branch { state_mask, hash, store_in_db_trie } => {
1596                    if let Some((hash, store_in_db_trie)) =
1597                        hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
1598                    {
1599                        buffers.rlp_node_stack.push(RlpNodeStackItem {
1600                            path,
1601                            rlp_node: RlpNode::word_rlp(&hash),
1602                            node_type: SparseNodeType::Branch {
1603                                store_in_db_trie: Some(store_in_db_trie),
1604                            },
1605                        });
1606                        continue
1607                    }
1608                    let retain_updates = self.updates.is_some() && prefix_set_contains(&path);
1609
1610                    buffers.branch_child_buf.clear();
1611                    // Walk children in a reverse order from `f` to `0`, so we pop the `0` first
1612                    // from the stack and keep walking in the sorted order.
1613                    for bit in CHILD_INDEX_RANGE.rev() {
1614                        if state_mask.is_bit_set(bit) {
1615                            let mut child = path;
1616                            child.push_unchecked(bit);
1617                            buffers.branch_child_buf.push(child);
1618                        }
1619                    }
1620
1621                    buffers
1622                        .branch_value_stack_buf
1623                        .resize(buffers.branch_child_buf.len(), Default::default());
1624                    let mut added_children = false;
1625
1626                    let mut tree_mask = TrieMask::default();
1627                    let mut hash_mask = TrieMask::default();
1628                    let mut hashes = Vec::new();
1629
1630                    // Lazy lookup for branch node masks - shared across loop iterations
1631                    let mut path_masks_storage = None;
1632                    let mut path_masks = || {
1633                        *path_masks_storage.get_or_insert_with(|| self.branch_node_masks.get(&path))
1634                    };
1635
1636                    for (i, child_path) in buffers.branch_child_buf.iter().enumerate() {
1637                        if buffers.rlp_node_stack.last().is_some_and(|e| &e.path == child_path) {
1638                            let RlpNodeStackItem {
1639                                path: _,
1640                                rlp_node: child,
1641                                node_type: child_node_type,
1642                            } = buffers.rlp_node_stack.pop().unwrap();
1643
1644                            // Update the masks only if we need to retain trie updates
1645                            if retain_updates {
1646                                // SAFETY: it's a child, so it's never empty
1647                                let last_child_nibble = child_path.last().unwrap();
1648
1649                                // Determine whether we need to set trie mask bit.
1650                                let should_set_tree_mask_bit = if let Some(store_in_db_trie) =
1651                                    child_node_type.store_in_db_trie()
1652                                {
1653                                    // A branch or an extension node explicitly set the
1654                                    // `store_in_db_trie` flag
1655                                    store_in_db_trie
1656                                } else {
1657                                    // A blinded node has the tree mask bit set
1658                                    child_node_type.is_hash() &&
1659                                        path_masks().is_some_and(|masks| {
1660                                            masks.tree_mask.is_bit_set(last_child_nibble)
1661                                        })
1662                                };
1663                                if should_set_tree_mask_bit {
1664                                    tree_mask.set_bit(last_child_nibble);
1665                                }
1666
1667                                // Set the hash mask. If a child node is a revealed branch node OR
1668                                // is a blinded node that has its hash mask bit set according to the
1669                                // database, set the hash mask bit and save the hash.
1670                                let hash = child.as_hash().filter(|_| {
1671                                    child_node_type.is_branch() ||
1672                                        (child_node_type.is_hash() &&
1673                                            path_masks().is_some_and(|masks| {
1674                                                masks.hash_mask.is_bit_set(last_child_nibble)
1675                                            }))
1676                                });
1677                                if let Some(hash) = hash {
1678                                    hash_mask.set_bit(last_child_nibble);
1679                                    hashes.push(hash);
1680                                }
1681                            }
1682
1683                            // Insert children in the resulting buffer in a normal order,
1684                            // because initially we iterated in reverse.
1685                            // SAFETY: i < len and len is never 0
1686                            let original_idx = buffers.branch_child_buf.len() - i - 1;
1687                            buffers.branch_value_stack_buf[original_idx] = child;
1688                            added_children = true;
1689                        } else {
1690                            debug_assert!(!added_children);
1691                            buffers.path_stack.push(RlpNodePathStackItem {
1692                                level,
1693                                path,
1694                                is_in_prefix_set,
1695                            });
1696                            buffers.path_stack.extend(buffers.branch_child_buf.drain(..).map(
1697                                |path| RlpNodePathStackItem {
1698                                    level: level + 1,
1699                                    path,
1700                                    is_in_prefix_set: None,
1701                                },
1702                            ));
1703                            continue 'main
1704                        }
1705                    }
1706
1707                    trace!(
1708                        target: "trie::sparse",
1709                        ?path,
1710                        ?tree_mask,
1711                        ?hash_mask,
1712                        "Branch node masks"
1713                    );
1714
1715                    rlp_buf.clear();
1716                    let branch_node_ref =
1717                        BranchNodeRef::new(&buffers.branch_value_stack_buf, *state_mask);
1718                    let rlp_node = branch_node_ref.rlp(rlp_buf);
1719                    *hash = rlp_node.as_hash();
1720
1721                    // Save a branch node update only if it's not a root node, and we need to
1722                    // persist updates.
1723                    let store_in_db_trie_value = if let Some(updates) =
1724                        self.updates.as_mut().filter(|_| retain_updates && !path.is_empty())
1725                    {
1726                        let store_in_db_trie = !tree_mask.is_empty() || !hash_mask.is_empty();
1727                        if store_in_db_trie {
1728                            // Store in DB trie if there are either any children that are stored in
1729                            // the DB trie, or any children represent hashed values
1730                            hashes.reverse();
1731                            let branch_node = BranchNodeCompact::new(
1732                                *state_mask,
1733                                tree_mask,
1734                                hash_mask,
1735                                hashes,
1736                                hash.filter(|_| path.is_empty()),
1737                            );
1738                            updates.updated_nodes.insert(path, branch_node);
1739                        } else {
1740                            // New tree and hash masks are empty - check previous state
1741                            let prev_had_masks = path_masks().is_some_and(|m| {
1742                                !m.tree_mask.is_empty() || !m.hash_mask.is_empty()
1743                            });
1744                            updates.updated_nodes.remove(&path);
1745                            if prev_had_masks {
1746                                // Previously had masks, now empty - mark as removed
1747                                updates.removed_nodes.insert(path);
1748                            }
1749                        }
1750
1751                        store_in_db_trie
1752                    } else {
1753                        false
1754                    };
1755                    *store_in_db_trie = Some(store_in_db_trie_value);
1756
1757                    (
1758                        rlp_node,
1759                        SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie_value) },
1760                    )
1761                }
1762            };
1763
1764            trace!(
1765                target: "trie::sparse",
1766                ?_starting_path,
1767                ?level,
1768                ?path,
1769                ?node,
1770                ?node_type,
1771                ?is_in_prefix_set,
1772                "Added node to rlp node stack"
1773            );
1774
1775            buffers.rlp_node_stack.push(RlpNodeStackItem { path, rlp_node, node_type });
1776        }
1777
1778        debug_assert_eq!(buffers.rlp_node_stack.len(), 1);
1779        buffers.rlp_node_stack.pop().unwrap().rlp_node
1780    }
1781}
1782
1783/// Enum representing sparse trie node type.
1784#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1785pub enum SparseNodeType {
1786    /// Empty trie node.
1787    Empty,
1788    /// A placeholder that stores only the hash for a node that has not been fully revealed.
1789    Hash,
1790    /// Sparse leaf node.
1791    Leaf,
1792    /// Sparse extension node.
1793    Extension {
1794        /// A flag indicating whether the extension node should be stored in the database.
1795        store_in_db_trie: Option<bool>,
1796    },
1797    /// Sparse branch node.
1798    Branch {
1799        /// A flag indicating whether the branch node should be stored in the database.
1800        store_in_db_trie: Option<bool>,
1801    },
1802}
1803
1804impl SparseNodeType {
1805    /// Returns true if the node is a hash node.
1806    pub const fn is_hash(&self) -> bool {
1807        matches!(self, Self::Hash)
1808    }
1809
1810    /// Returns true if the node is a branch node.
1811    pub const fn is_branch(&self) -> bool {
1812        matches!(self, Self::Branch { .. })
1813    }
1814
1815    /// Returns true if the node should be stored in the database.
1816    pub const fn store_in_db_trie(&self) -> Option<bool> {
1817        match *self {
1818            Self::Extension { store_in_db_trie } | Self::Branch { store_in_db_trie } => {
1819                store_in_db_trie
1820            }
1821            _ => None,
1822        }
1823    }
1824}
1825
1826/// Enum representing trie nodes in sparse trie.
1827#[derive(Debug, Clone, PartialEq, Eq)]
1828pub enum SparseNode {
1829    /// Empty trie node.
1830    Empty,
1831    /// The hash of the node that was not revealed.
1832    Hash(B256),
1833    /// Sparse leaf node with remaining key suffix.
1834    Leaf {
1835        /// Remaining key suffix for the leaf node.
1836        key: Nibbles,
1837        /// Pre-computed hash of the sparse node.
1838        /// Can be reused unless this trie path has been updated.
1839        hash: Option<B256>,
1840    },
1841    /// Sparse extension node with key.
1842    Extension {
1843        /// The key slice stored by this extension node.
1844        key: Nibbles,
1845        /// Pre-computed hash of the sparse node.
1846        /// Can be reused unless this trie path has been updated.
1847        ///
1848        /// If [`None`], then the value is not known and should be calculated from scratch.
1849        hash: Option<B256>,
1850        /// Pre-computed flag indicating whether the trie node should be stored in the database.
1851        /// Can be reused unless this trie path has been updated.
1852        ///
1853        /// If [`None`], then the value is not known and should be calculated from scratch.
1854        store_in_db_trie: Option<bool>,
1855    },
1856    /// Sparse branch node with state mask.
1857    Branch {
1858        /// The bitmask representing children present in the branch node.
1859        state_mask: TrieMask,
1860        /// Pre-computed hash of the sparse node.
1861        /// Can be reused unless this trie path has been updated.
1862        ///
1863        /// If [`None`], then the value is not known and should be calculated from scratch.
1864        hash: Option<B256>,
1865        /// Pre-computed flag indicating whether the trie node should be stored in the database.
1866        /// Can be reused unless this trie path has been updated.
1867        ///
1868        /// If [`None`], then the value is not known and should be calculated from scratch.
1869        store_in_db_trie: Option<bool>,
1870    },
1871}
1872
1873impl SparseNode {
1874    /// Create new sparse node from [`TrieNode`].
1875    pub fn from_node(node: TrieNode) -> Self {
1876        match node {
1877            TrieNode::EmptyRoot => Self::Empty,
1878            TrieNode::Leaf(leaf) => Self::new_leaf(leaf.key),
1879            TrieNode::Extension(ext) => Self::new_ext(ext.key),
1880            TrieNode::Branch(branch) => Self::new_branch(branch.state_mask),
1881        }
1882    }
1883
1884    /// Create new [`SparseNode::Branch`] from state mask.
1885    pub const fn new_branch(state_mask: TrieMask) -> Self {
1886        Self::Branch { state_mask, hash: None, store_in_db_trie: None }
1887    }
1888
1889    /// Create new [`SparseNode::Branch`] with two bits set.
1890    pub const fn new_split_branch(bit_a: u8, bit_b: u8) -> Self {
1891        let state_mask = TrieMask::new(
1892            // set bits for both children
1893            (1u16 << bit_a) | (1u16 << bit_b),
1894        );
1895        Self::Branch { state_mask, hash: None, store_in_db_trie: None }
1896    }
1897
1898    /// Create new [`SparseNode::Extension`] from the key slice.
1899    pub const fn new_ext(key: Nibbles) -> Self {
1900        Self::Extension { key, hash: None, store_in_db_trie: None }
1901    }
1902
1903    /// Create new [`SparseNode::Leaf`] from leaf key and value.
1904    pub const fn new_leaf(key: Nibbles) -> Self {
1905        Self::Leaf { key, hash: None }
1906    }
1907
1908    /// Returns `true` if the node is a hash node.
1909    pub const fn is_hash(&self) -> bool {
1910        matches!(self, Self::Hash(_))
1911    }
1912
1913    /// Returns the hash of the node if it exists.
1914    pub const fn hash(&self) -> Option<B256> {
1915        match self {
1916            Self::Empty => None,
1917            Self::Hash(hash) => Some(*hash),
1918            Self::Leaf { hash, .. } | Self::Extension { hash, .. } | Self::Branch { hash, .. } => {
1919                *hash
1920            }
1921        }
1922    }
1923
1924    /// Sets the hash of the node for testing purposes.
1925    ///
1926    /// For [`SparseNode::Empty`] and [`SparseNode::Hash`] nodes, this method does nothing.
1927    #[cfg(any(test, feature = "test-utils"))]
1928    pub const fn set_hash(&mut self, new_hash: Option<B256>) {
1929        match self {
1930            Self::Empty | Self::Hash(_) => {
1931                // Cannot set hash for Empty or Hash nodes
1932            }
1933            Self::Leaf { hash, .. } | Self::Extension { hash, .. } | Self::Branch { hash, .. } => {
1934                *hash = new_hash;
1935            }
1936        }
1937    }
1938}
1939
1940/// A helper struct used to store information about a node that has been removed
1941/// during a deletion operation.
1942#[derive(Debug)]
1943struct RemovedSparseNode {
1944    /// The path at which the node was located.
1945    path: Nibbles,
1946    /// The removed node
1947    node: SparseNode,
1948    /// For branch nodes, an optional nibble that should be unset due to the node being removed.
1949    ///
1950    /// During leaf deletion, this identifies the specific branch nibble path that
1951    /// connects to the leaf being deleted. Then when restructuring the trie after deletion,
1952    /// this nibble position will be cleared from the branch node's to
1953    /// indicate that the child no longer exists.
1954    ///
1955    /// This is only set for branch nodes that have a direct path to the leaf being deleted.
1956    unset_branch_nibble: Option<u8>,
1957}
1958
1959/// Collection of reusable buffers for [`SerialSparseTrie::rlp_node`] calculations.
1960///
1961/// These buffers reduce allocations when computing RLP representations during trie updates.
1962#[derive(Debug, Default)]
1963pub struct RlpNodeBuffers {
1964    /// Stack of RLP node paths
1965    path_stack: Vec<RlpNodePathStackItem>,
1966    /// Stack of RLP nodes
1967    rlp_node_stack: Vec<RlpNodeStackItem>,
1968    /// Reusable branch child path
1969    branch_child_buf: SmallVec<[Nibbles; 16]>,
1970    /// Reusable branch value stack
1971    branch_value_stack_buf: SmallVec<[RlpNode; 16]>,
1972}
1973
1974impl RlpNodeBuffers {
1975    /// Creates a new instance of buffers with the root path on the stack.
1976    fn new_with_root_path() -> Self {
1977        Self {
1978            path_stack: vec![RlpNodePathStackItem {
1979                level: 0,
1980                path: Nibbles::default(),
1981                is_in_prefix_set: None,
1982            }],
1983            rlp_node_stack: Vec::new(),
1984            branch_child_buf: SmallVec::<[Nibbles; 16]>::new_const(),
1985            branch_value_stack_buf: SmallVec::<[RlpNode; 16]>::new_const(),
1986        }
1987    }
1988}
1989
1990/// RLP node path stack item.
1991#[derive(Clone, PartialEq, Eq, Debug)]
1992pub struct RlpNodePathStackItem {
1993    /// Level at which the node is located. Higher numbers correspond to lower levels in the trie.
1994    pub level: usize,
1995    /// Path to the node.
1996    pub path: Nibbles,
1997    /// Whether the path is in the prefix set. If [`None`], then unknown yet.
1998    pub is_in_prefix_set: Option<bool>,
1999}
2000
2001/// RLP node stack item.
2002#[derive(Clone, PartialEq, Eq, Debug)]
2003pub struct RlpNodeStackItem {
2004    /// Path to the node.
2005    pub path: Nibbles,
2006    /// RLP node.
2007    pub rlp_node: RlpNode,
2008    /// Type of the node.
2009    pub node_type: SparseNodeType,
2010}
2011
2012impl SparseTrieUpdates {
2013    /// Create new wiped sparse trie updates.
2014    pub fn wiped() -> Self {
2015        Self { wiped: true, ..Default::default() }
2016    }
2017
2018    /// Clears the updates, but keeps the backing data structures allocated.
2019    ///
2020    /// Sets `wiped` to `false`.
2021    pub fn clear(&mut self) {
2022        self.updated_nodes.clear();
2023        self.removed_nodes.clear();
2024        self.wiped = false;
2025    }
2026
2027    /// Extends the updates with another set of updates.
2028    pub fn extend(&mut self, other: Self) {
2029        self.updated_nodes.extend(other.updated_nodes);
2030        self.removed_nodes.extend(other.removed_nodes);
2031        self.wiped |= other.wiped;
2032    }
2033}
2034
2035#[cfg(test)]
2036mod find_leaf_tests {
2037    use super::*;
2038    use crate::provider::DefaultTrieNodeProvider;
2039    use alloy_rlp::Encodable;
2040    use assert_matches::assert_matches;
2041    use reth_primitives_traits::Account;
2042    use reth_trie_common::LeafNode;
2043
2044    // Helper to create some test values
2045    fn encode_value(nonce: u64) -> Vec<u8> {
2046        let account = Account { nonce, ..Default::default() };
2047        let trie_account = account.into_trie_account(EMPTY_ROOT_HASH);
2048        let mut buf = Vec::new();
2049        trie_account.encode(&mut buf);
2050        buf
2051    }
2052
2053    const VALUE_A: fn() -> Vec<u8> = || encode_value(1);
2054    const VALUE_B: fn() -> Vec<u8> = || encode_value(2);
2055
2056    #[test]
2057    fn find_leaf_existing_leaf() {
2058        // Create a simple trie with one leaf
2059        let provider = DefaultTrieNodeProvider;
2060        let mut sparse = SerialSparseTrie::default();
2061        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
2062        let value = b"test_value".to_vec();
2063
2064        sparse.update_leaf(path, value.clone(), &provider).unwrap();
2065
2066        // Check that the leaf exists
2067        let result = sparse.find_leaf(&path, None);
2068        assert_matches!(result, Ok(LeafLookup::Exists));
2069
2070        // Check with expected value matching
2071        let result = sparse.find_leaf(&path, Some(&value));
2072        assert_matches!(result, Ok(LeafLookup::Exists));
2073    }
2074
2075    #[test]
2076    fn find_leaf_value_mismatch() {
2077        // Create a simple trie with one leaf
2078        let provider = DefaultTrieNodeProvider;
2079        let mut sparse = SerialSparseTrie::default();
2080        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
2081        let value = b"test_value".to_vec();
2082        let wrong_value = b"wrong_value".to_vec();
2083
2084        sparse.update_leaf(path, value, &provider).unwrap();
2085
2086        // Check with wrong expected value
2087        let result = sparse.find_leaf(&path, Some(&wrong_value));
2088        assert_matches!(
2089            result,
2090            Err(LeafLookupError::ValueMismatch { path: p, expected: Some(e), actual: _a }) if p == path && e == wrong_value
2091        );
2092    }
2093
2094    #[test]
2095    fn find_leaf_not_found_empty_trie() {
2096        // Empty trie
2097        let sparse = SerialSparseTrie::default();
2098        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
2099
2100        // Leaf should not exist
2101        let result = sparse.find_leaf(&path, None);
2102        assert_matches!(result, Ok(LeafLookup::NonExistent));
2103    }
2104
2105    #[test]
2106    fn find_leaf_empty_trie() {
2107        let sparse = SerialSparseTrie::default();
2108        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2109
2110        let result = sparse.find_leaf(&path, None);
2111        assert_matches!(result, Ok(LeafLookup::NonExistent));
2112    }
2113
2114    #[test]
2115    fn find_leaf_exists_no_value_check() {
2116        let provider = DefaultTrieNodeProvider;
2117        let mut sparse = SerialSparseTrie::default();
2118        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2119        sparse.update_leaf(path, VALUE_A(), &provider).unwrap();
2120
2121        let result = sparse.find_leaf(&path, None);
2122        assert_matches!(result, Ok(LeafLookup::Exists));
2123    }
2124
2125    #[test]
2126    fn find_leaf_exists_with_value_check_ok() {
2127        let provider = DefaultTrieNodeProvider;
2128        let mut sparse = SerialSparseTrie::default();
2129        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2130        let value = VALUE_A();
2131        sparse.update_leaf(path, value.clone(), &provider).unwrap();
2132
2133        let result = sparse.find_leaf(&path, Some(&value));
2134        assert_matches!(result, Ok(LeafLookup::Exists));
2135    }
2136
2137    #[test]
2138    fn find_leaf_exclusion_branch_divergence() {
2139        let provider = DefaultTrieNodeProvider;
2140        let mut sparse = SerialSparseTrie::default();
2141        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); // Creates branch at 0x12
2142        let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]); // Belongs to same branch
2143        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]); // Diverges at nibble 7
2144
2145        sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
2146        sparse.update_leaf(path2, VALUE_B(), &provider).unwrap();
2147
2148        let result = sparse.find_leaf(&search_path, None);
2149        assert_matches!(result, Ok(LeafLookup::NonExistent));
2150    }
2151
2152    #[test]
2153    fn find_leaf_exclusion_extension_divergence() {
2154        let provider = DefaultTrieNodeProvider;
2155        let mut sparse = SerialSparseTrie::default();
2156        // This will create an extension node at root with key 0x12
2157        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
2158        // This path diverges from the extension key
2159        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]);
2160
2161        sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
2162
2163        let result = sparse.find_leaf(&search_path, None);
2164        assert_matches!(result, Ok(LeafLookup::NonExistent));
2165    }
2166
2167    #[test]
2168    fn find_leaf_exclusion_leaf_divergence() {
2169        let provider = DefaultTrieNodeProvider;
2170        let mut sparse = SerialSparseTrie::default();
2171        let existing_leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2172        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
2173
2174        sparse.update_leaf(existing_leaf_path, VALUE_A(), &provider).unwrap();
2175
2176        let result = sparse.find_leaf(&search_path, None);
2177        assert_matches!(result, Ok(LeafLookup::NonExistent));
2178    }
2179
2180    #[test]
2181    fn find_leaf_exclusion_path_ends_at_branch() {
2182        let provider = DefaultTrieNodeProvider;
2183        let mut sparse = SerialSparseTrie::default();
2184        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); // Creates branch at 0x12
2185        let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]);
2186        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2]); // Path of the branch itself
2187
2188        sparse.update_leaf(path1, VALUE_A(), &provider).unwrap();
2189        sparse.update_leaf(path2, VALUE_B(), &provider).unwrap();
2190
2191        let result = sparse.find_leaf(&search_path, None);
2192        assert_matches!(result, Ok(LeafLookup::NonExistent));
2193    }
2194
2195    #[test]
2196    fn find_leaf_error_trie_node_at_leaf_path() {
2197        // Scenario: The node *at* the leaf path is blinded.
2198        let blinded_hash = B256::repeat_byte(0xBB);
2199        let leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2200
2201        let mut nodes = alloy_primitives::map::HashMap::default();
2202        // Create path to the blinded node
2203        nodes.insert(
2204            Nibbles::default(),
2205            SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x1, 0x2])),
2206        ); // Ext 0x12
2207        nodes.insert(
2208            Nibbles::from_nibbles_unchecked([0x1, 0x2]),
2209            SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x3])),
2210        ); // Ext 0x123
2211        nodes.insert(
2212            Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3]),
2213            SparseNode::new_branch(TrieMask::new(0b10000)),
2214        ); // Branch at 0x123, child 4
2215        nodes.insert(leaf_path, SparseNode::Hash(blinded_hash)); // Blinded node at 0x1234
2216
2217        let sparse = SerialSparseTrie {
2218            nodes,
2219            branch_node_masks: Default::default(),
2220            /* The value is not in the values map, or else it would early return */
2221            values: Default::default(),
2222            prefix_set: Default::default(),
2223            updates: None,
2224            rlp_buf: Vec::new(),
2225        };
2226
2227        let result = sparse.find_leaf(&leaf_path, None);
2228
2229        // Should error because it hit the blinded node exactly at the leaf path
2230        assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
2231            if path == leaf_path && hash == blinded_hash
2232        );
2233    }
2234
2235    #[test]
2236    fn find_leaf_error_trie_node() {
2237        let blinded_hash = B256::repeat_byte(0xAA);
2238        let path_to_blind = Nibbles::from_nibbles_unchecked([0x1]);
2239        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
2240
2241        let mut nodes = HashMap::default();
2242
2243        // Root is a branch with child 0x1 (blinded) and 0x5 (revealed leaf)
2244        // So we set Bit 1 and Bit 5 in the state_mask
2245        let state_mask = TrieMask::new(0b100010);
2246        nodes.insert(Nibbles::default(), SparseNode::new_branch(state_mask));
2247
2248        nodes.insert(path_to_blind, SparseNode::Hash(blinded_hash));
2249        let path_revealed = Nibbles::from_nibbles_unchecked([0x5]);
2250        let path_revealed_leaf = Nibbles::from_nibbles_unchecked([0x5, 0x6, 0x7, 0x8]);
2251        nodes.insert(
2252            path_revealed,
2253            SparseNode::new_leaf(Nibbles::from_nibbles_unchecked([0x6, 0x7, 0x8])),
2254        );
2255
2256        let mut values = HashMap::default();
2257        values.insert(path_revealed_leaf, VALUE_A());
2258
2259        let sparse = SerialSparseTrie {
2260            nodes,
2261            branch_node_masks: Default::default(),
2262            values,
2263            prefix_set: Default::default(),
2264            updates: None,
2265            rlp_buf: Vec::new(),
2266        };
2267
2268        let result = sparse.find_leaf(&search_path, None);
2269
2270        // Should error because it hit the blinded node at path 0x1
2271        assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
2272            if path == path_to_blind && hash == blinded_hash
2273        );
2274    }
2275
2276    #[test]
2277    fn find_leaf_error_trie_node_via_reveal() {
2278        let blinded_hash = B256::repeat_byte(0xAA);
2279        let path_to_blind = Nibbles::from_nibbles_unchecked([0x1]); // Path of the blinded node itself
2280        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); // Path we will search for
2281
2282        let revealed_leaf_prefix = Nibbles::from_nibbles_unchecked([0x5]);
2283        let revealed_leaf_suffix = Nibbles::from_nibbles_unchecked([0x6, 0x7, 0x8]);
2284        let revealed_leaf_full_path = Nibbles::from_nibbles_unchecked([0x5, 0x6, 0x7, 0x8]);
2285        let revealed_value = VALUE_A();
2286
2287        // 1. Construct the RLP representation of the children for the root branch
2288        let rlp_node_child1 = RlpNode::word_rlp(&blinded_hash); // Blinded node
2289
2290        let leaf_node_child5 = LeafNode::new(revealed_leaf_suffix, revealed_value.clone());
2291        let leaf_node_child5_rlp_buf = alloy_rlp::encode(&leaf_node_child5);
2292        let hash_of_child5 = keccak256(&leaf_node_child5_rlp_buf);
2293        let rlp_node_child5 = RlpNode::word_rlp(&hash_of_child5);
2294
2295        // 2. Construct the root BranchNode using the RLP of its children
2296        // The stack order depends on the bit indices (1 and 5)
2297        let root_branch_node = reth_trie_common::BranchNode::new(
2298            vec![rlp_node_child1, rlp_node_child5], // Child 1 first, then Child 5
2299            TrieMask::new(0b100010),                // Mask with bits 1 and 5 set
2300        );
2301        let root_trie_node = TrieNode::Branch(root_branch_node);
2302
2303        // 3. Initialize the sparse trie using from_root
2304        // This will internally create Hash nodes for paths "1" and "5" initially.
2305        let mut sparse = SerialSparseTrie::from_root(root_trie_node, TrieMasks::none(), false)
2306            .expect("Failed to create trie from root");
2307
2308        // Assertions before we reveal child5
2309        assert_matches!(sparse.nodes.get(&Nibbles::default()), Some(SparseNode::Branch { state_mask, .. }) if *state_mask == TrieMask::new(0b100010)); // Here we check that 1 and 5 are set in the state_mask
2310        assert_matches!(sparse.nodes.get(&path_to_blind), Some(SparseNode::Hash(h)) if *h == blinded_hash );
2311        assert!(sparse.nodes.get(&revealed_leaf_prefix).unwrap().is_hash()); // Child 5 is initially a hash of its RLP
2312        assert!(sparse.values.is_empty());
2313
2314        // 4. Explicitly reveal the leaf node for child 5
2315        sparse
2316            .reveal_node(revealed_leaf_prefix, TrieNode::Leaf(leaf_node_child5), TrieMasks::none())
2317            .expect("Failed to reveal leaf node");
2318
2319        // Assertions after we reveal child 5
2320        assert_matches!(sparse.nodes.get(&Nibbles::default()), Some(SparseNode::Branch { state_mask, .. }) if *state_mask == TrieMask::new(0b100010));
2321        assert_matches!(sparse.nodes.get(&path_to_blind), Some(SparseNode::Hash(h)) if *h == blinded_hash );
2322        assert_matches!(sparse.nodes.get(&revealed_leaf_prefix), Some(SparseNode::Leaf { key, .. }) if *key == revealed_leaf_suffix);
2323        assert_eq!(sparse.values.get(&revealed_leaf_full_path), Some(&revealed_value));
2324
2325        let result = sparse.find_leaf(&search_path, None);
2326
2327        // 5. Assert the expected error
2328        // Should error because it hit the blinded node at path "1" only node at "5" was revealed
2329        assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
2330            if path == path_to_blind && hash == blinded_hash
2331        );
2332    }
2333}
2334
2335#[cfg(test)]
2336mod tests {
2337    use super::*;
2338    use crate::provider::DefaultTrieNodeProvider;
2339    use alloy_primitives::{map::B256Set, U256};
2340    use alloy_rlp::Encodable;
2341    use assert_matches::assert_matches;
2342    use itertools::Itertools;
2343    use prop::sample::SizeRange;
2344    use proptest::prelude::*;
2345    use proptest_arbitrary_interop::arb;
2346    use reth_primitives_traits::Account;
2347    use reth_provider::{test_utils::create_test_provider_factory, TrieWriter};
2348    use reth_trie::{
2349        hashed_cursor::{noop::NoopHashedCursor, HashedPostStateCursor},
2350        node_iter::{TrieElement, TrieNodeIter},
2351        trie_cursor::{noop::NoopAccountTrieCursor, TrieCursor, TrieCursorFactory},
2352        walker::TrieWalker,
2353        BranchNode, ExtensionNode, HashedPostState, LeafNode,
2354    };
2355    use reth_trie_common::{
2356        proof::{ProofNodes, ProofRetainer},
2357        updates::TrieUpdates,
2358        HashBuilder,
2359    };
2360    use reth_trie_db::DatabaseTrieCursorFactory;
2361    use std::collections::{BTreeMap, BTreeSet};
2362
2363    /// Pad nibbles to the length of a B256 hash with zeros on the left.
2364    fn pad_nibbles_left(nibbles: Nibbles) -> Nibbles {
2365        let mut base =
2366            Nibbles::from_nibbles_unchecked(vec![0; B256::len_bytes() * 2 - nibbles.len()]);
2367        base.extend(&nibbles);
2368        base
2369    }
2370
2371    /// Pad nibbles to the length of a B256 hash with zeros on the right.
2372    fn pad_nibbles_right(mut nibbles: Nibbles) -> Nibbles {
2373        nibbles.extend(&Nibbles::from_nibbles_unchecked(vec![
2374            0;
2375            B256::len_bytes() * 2 - nibbles.len()
2376        ]));
2377        nibbles
2378    }
2379
2380    /// Calculate the state root by feeding the provided state to the hash builder and retaining the
2381    /// proofs for the provided targets.
2382    ///
2383    /// Returns the state root and the retained proof nodes.
2384    fn run_hash_builder(
2385        state: impl IntoIterator<Item = (Nibbles, Account)> + Clone,
2386        trie_cursor: impl TrieCursor,
2387        destroyed_accounts: B256Set,
2388        proof_targets: impl IntoIterator<Item = Nibbles>,
2389    ) -> (B256, TrieUpdates, ProofNodes, HashMap<Nibbles, TrieMask>, HashMap<Nibbles, TrieMask>)
2390    {
2391        let mut account_rlp = Vec::new();
2392
2393        let mut hash_builder = HashBuilder::default()
2394            .with_updates(true)
2395            .with_proof_retainer(ProofRetainer::from_iter(proof_targets));
2396
2397        let mut prefix_set = PrefixSetMut::default();
2398        prefix_set.extend_keys(state.clone().into_iter().map(|(nibbles, _)| nibbles));
2399        prefix_set.extend_keys(destroyed_accounts.iter().map(Nibbles::unpack));
2400        let walker = TrieWalker::<_>::state_trie(trie_cursor, prefix_set.freeze())
2401            .with_deletions_retained(true);
2402        let hashed_post_state = HashedPostState::default()
2403            .with_accounts(state.into_iter().map(|(nibbles, account)| {
2404                (nibbles.pack().into_inner().unwrap().into(), Some(account))
2405            }))
2406            .into_sorted();
2407        let mut node_iter = TrieNodeIter::state_trie(
2408            walker,
2409            HashedPostStateCursor::new_account(
2410                NoopHashedCursor::<Account>::default(),
2411                &hashed_post_state,
2412            ),
2413        );
2414
2415        while let Some(node) = node_iter.try_next().unwrap() {
2416            match node {
2417                TrieElement::Branch(branch) => {
2418                    hash_builder.add_branch(branch.key, branch.value, branch.children_are_in_trie);
2419                }
2420                TrieElement::Leaf(key, account) => {
2421                    let account = account.into_trie_account(EMPTY_ROOT_HASH);
2422                    account.encode(&mut account_rlp);
2423
2424                    hash_builder.add_leaf(Nibbles::unpack(key), &account_rlp);
2425                    account_rlp.clear();
2426                }
2427            }
2428        }
2429        let root = hash_builder.root();
2430        let proof_nodes = hash_builder.take_proof_nodes();
2431        let branch_node_hash_masks = hash_builder
2432            .updated_branch_nodes
2433            .clone()
2434            .unwrap_or_default()
2435            .iter()
2436            .map(|(path, node)| (*path, node.hash_mask))
2437            .collect();
2438        let branch_node_tree_masks = hash_builder
2439            .updated_branch_nodes
2440            .clone()
2441            .unwrap_or_default()
2442            .iter()
2443            .map(|(path, node)| (*path, node.tree_mask))
2444            .collect();
2445
2446        let mut trie_updates = TrieUpdates::default();
2447        let removed_keys = node_iter.walker.take_removed_keys();
2448        trie_updates.finalize(hash_builder, removed_keys, destroyed_accounts);
2449
2450        (root, trie_updates, proof_nodes, branch_node_hash_masks, branch_node_tree_masks)
2451    }
2452
2453    /// Assert that the sparse trie nodes and the proof nodes from the hash builder are equal.
2454    fn assert_eq_sparse_trie_proof_nodes(sparse_trie: &SerialSparseTrie, proof_nodes: ProofNodes) {
2455        let proof_nodes = proof_nodes
2456            .into_nodes_sorted()
2457            .into_iter()
2458            .map(|(path, node)| (path, TrieNode::decode(&mut node.as_ref()).unwrap()));
2459
2460        let sparse_nodes = sparse_trie.nodes.iter().sorted_by_key(|(path, _)| *path);
2461
2462        for ((proof_node_path, proof_node), (sparse_node_path, sparse_node)) in
2463            proof_nodes.zip(sparse_nodes)
2464        {
2465            assert_eq!(&proof_node_path, sparse_node_path);
2466
2467            let equals = match (&proof_node, &sparse_node) {
2468                // Both nodes are empty
2469                (TrieNode::EmptyRoot, SparseNode::Empty) => true,
2470                // Both nodes are branches and have the same state mask
2471                (
2472                    TrieNode::Branch(BranchNode { state_mask: proof_state_mask, .. }),
2473                    SparseNode::Branch { state_mask: sparse_state_mask, .. },
2474                ) => proof_state_mask == sparse_state_mask,
2475                // Both nodes are extensions and have the same key
2476                (
2477                    TrieNode::Extension(ExtensionNode { key: proof_key, .. }),
2478                    SparseNode::Extension { key: sparse_key, .. },
2479                ) |
2480                // Both nodes are leaves and have the same key
2481                (
2482                    TrieNode::Leaf(LeafNode { key: proof_key, .. }),
2483                    SparseNode::Leaf { key: sparse_key, .. },
2484                ) => proof_key == sparse_key,
2485                // Empty and hash nodes are specific to the sparse trie, skip them
2486                (_, SparseNode::Empty | SparseNode::Hash(_)) => continue,
2487                _ => false,
2488            };
2489            assert!(
2490                equals,
2491                "path: {proof_node_path:?}\nproof node: {proof_node:?}\nsparse node: {sparse_node:?}"
2492            );
2493        }
2494    }
2495
2496    #[test]
2497    fn sparse_trie_is_blind() {
2498        assert!(SparseTrie::<SerialSparseTrie>::blind().is_blind());
2499        assert!(!SparseTrie::<SerialSparseTrie>::revealed_empty().is_blind());
2500    }
2501
2502    #[test]
2503    fn sparse_trie_empty_update_one() {
2504        let key = Nibbles::unpack(B256::with_last_byte(42));
2505        let value = || Account::default();
2506        let value_encoded = || {
2507            let mut account_rlp = Vec::new();
2508            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2509            account_rlp
2510        };
2511
2512        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2513            run_hash_builder(
2514                [(key, value())],
2515                NoopAccountTrieCursor::default(),
2516                Default::default(),
2517                [key],
2518            );
2519
2520        let provider = DefaultTrieNodeProvider;
2521        let mut sparse = SerialSparseTrie::default().with_updates(true);
2522        sparse.update_leaf(key, value_encoded(), &provider).unwrap();
2523        let sparse_root = sparse.root();
2524        let sparse_updates = sparse.take_updates();
2525
2526        assert_eq!(sparse_root, hash_builder_root);
2527        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
2528        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2529    }
2530
2531    #[test]
2532    fn sparse_trie_empty_update_multiple_lower_nibbles() {
2533        reth_tracing::init_test_tracing();
2534
2535        let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::<Vec<_>>();
2536        let value = || Account::default();
2537        let value_encoded = || {
2538            let mut account_rlp = Vec::new();
2539            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2540            account_rlp
2541        };
2542
2543        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2544            run_hash_builder(
2545                paths.iter().copied().zip(std::iter::repeat_with(value)),
2546                NoopAccountTrieCursor::default(),
2547                Default::default(),
2548                paths.clone(),
2549            );
2550
2551        let provider = DefaultTrieNodeProvider;
2552        let mut sparse = SerialSparseTrie::default().with_updates(true);
2553        for path in &paths {
2554            sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
2555        }
2556        let sparse_root = sparse.root();
2557        let sparse_updates = sparse.take_updates();
2558
2559        assert_eq!(sparse_root, hash_builder_root);
2560        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
2561        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2562    }
2563
2564    #[test]
2565    fn sparse_trie_empty_update_multiple_upper_nibbles() {
2566        let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
2567        let value = || Account::default();
2568        let value_encoded = || {
2569            let mut account_rlp = Vec::new();
2570            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2571            account_rlp
2572        };
2573
2574        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2575            run_hash_builder(
2576                paths.iter().copied().zip(std::iter::repeat_with(value)),
2577                NoopAccountTrieCursor::default(),
2578                Default::default(),
2579                paths.clone(),
2580            );
2581
2582        let provider = DefaultTrieNodeProvider;
2583        let mut sparse = SerialSparseTrie::default().with_updates(true);
2584        for path in &paths {
2585            sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
2586        }
2587        let sparse_root = sparse.root();
2588        let sparse_updates = sparse.take_updates();
2589
2590        assert_eq!(sparse_root, hash_builder_root);
2591        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
2592        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2593    }
2594
2595    #[test]
2596    fn sparse_trie_empty_update_multiple() {
2597        let paths = (0..=255)
2598            .map(|b| {
2599                Nibbles::unpack(if b % 2 == 0 {
2600                    B256::repeat_byte(b)
2601                } else {
2602                    B256::with_last_byte(b)
2603                })
2604            })
2605            .collect::<Vec<_>>();
2606        let value = || Account::default();
2607        let value_encoded = || {
2608            let mut account_rlp = Vec::new();
2609            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2610            account_rlp
2611        };
2612
2613        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2614            run_hash_builder(
2615                paths.iter().sorted_unstable().copied().zip(std::iter::repeat_with(value)),
2616                NoopAccountTrieCursor::default(),
2617                Default::default(),
2618                paths.clone(),
2619            );
2620
2621        let provider = DefaultTrieNodeProvider;
2622        let mut sparse = SerialSparseTrie::default().with_updates(true);
2623        for path in &paths {
2624            sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
2625        }
2626        let sparse_root = sparse.root();
2627        let sparse_updates = sparse.take_updates();
2628
2629        assert_eq!(sparse_root, hash_builder_root);
2630        pretty_assertions::assert_eq!(
2631            BTreeMap::from_iter(sparse_updates.updated_nodes),
2632            BTreeMap::from_iter(hash_builder_updates.account_nodes)
2633        );
2634        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2635    }
2636
2637    #[test]
2638    fn sparse_trie_empty_update_repeated() {
2639        let paths = (0..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
2640        let old_value = Account { nonce: 1, ..Default::default() };
2641        let old_value_encoded = {
2642            let mut account_rlp = Vec::new();
2643            old_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2644            account_rlp
2645        };
2646        let new_value = Account { nonce: 2, ..Default::default() };
2647        let new_value_encoded = {
2648            let mut account_rlp = Vec::new();
2649            new_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
2650            account_rlp
2651        };
2652
2653        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2654            run_hash_builder(
2655                paths.iter().copied().zip(std::iter::repeat_with(|| old_value)),
2656                NoopAccountTrieCursor::default(),
2657                Default::default(),
2658                paths.clone(),
2659            );
2660
2661        let provider = DefaultTrieNodeProvider;
2662        let mut sparse = SerialSparseTrie::default().with_updates(true);
2663        for path in &paths {
2664            sparse.update_leaf(*path, old_value_encoded.clone(), &provider).unwrap();
2665        }
2666        let sparse_root = sparse.root();
2667        let sparse_updates = sparse.updates_ref();
2668
2669        assert_eq!(sparse_root, hash_builder_root);
2670        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
2671        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2672
2673        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
2674            run_hash_builder(
2675                paths.iter().copied().zip(std::iter::repeat_with(|| new_value)),
2676                NoopAccountTrieCursor::default(),
2677                Default::default(),
2678                paths.clone(),
2679            );
2680
2681        for path in &paths {
2682            sparse.update_leaf(*path, new_value_encoded.clone(), &provider).unwrap();
2683        }
2684        let sparse_root = sparse.root();
2685        let sparse_updates = sparse.take_updates();
2686
2687        assert_eq!(sparse_root, hash_builder_root);
2688        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
2689        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
2690    }
2691
2692    #[test]
2693    fn sparse_trie_remove_leaf() {
2694        reth_tracing::init_test_tracing();
2695
2696        let provider = DefaultTrieNodeProvider;
2697        let mut sparse = SerialSparseTrie::default();
2698
2699        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
2700
2701        sparse
2702            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
2703            .unwrap();
2704        sparse
2705            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
2706            .unwrap();
2707        sparse
2708            .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
2709            .unwrap();
2710        sparse
2711            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
2712            .unwrap();
2713        sparse
2714            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
2715            .unwrap();
2716        sparse
2717            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
2718            .unwrap();
2719
2720        // Extension (Key = 5)
2721        // └── Branch (Mask = 1011)
2722        //     ├── 0 -> Extension (Key = 23)
2723        //     │        └── Branch (Mask = 0101)
2724        //     │              ├── 1 -> Leaf (Key = 1, Path = 50231)
2725        //     │              └── 3 -> Leaf (Key = 3, Path = 50233)
2726        //     ├── 2 -> Leaf (Key = 013, Path = 52013)
2727        //     └── 3 -> Branch (Mask = 0101)
2728        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
2729        //                └── 3 -> Branch (Mask = 1010)
2730        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
2731        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
2732        pretty_assertions::assert_eq!(
2733            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2734            BTreeMap::from_iter([
2735                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
2736                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1101.into())),
2737                (
2738                    Nibbles::from_nibbles([0x5, 0x0]),
2739                    SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
2740                ),
2741                (
2742                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
2743                    SparseNode::new_branch(0b1010.into())
2744                ),
2745                (
2746                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
2747                    SparseNode::new_leaf(Nibbles::default())
2748                ),
2749                (
2750                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
2751                    SparseNode::new_leaf(Nibbles::default())
2752                ),
2753                (
2754                    Nibbles::from_nibbles([0x5, 0x2]),
2755                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x1, 0x3]))
2756                ),
2757                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
2758                (
2759                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
2760                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
2761                ),
2762                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
2763                (
2764                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
2765                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
2766                ),
2767                (
2768                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
2769                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
2770                )
2771            ])
2772        );
2773
2774        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), &provider).unwrap();
2775
2776        // Extension (Key = 5)
2777        // └── Branch (Mask = 1001)
2778        //     ├── 0 -> Extension (Key = 23)
2779        //     │        └── Branch (Mask = 0101)
2780        //     │              ├── 1 -> Leaf (Key = 0231, Path = 50231)
2781        //     │              └── 3 -> Leaf (Key = 0233, Path = 50233)
2782        //     └── 3 -> Branch (Mask = 0101)
2783        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
2784        //                └── 3 -> Branch (Mask = 1010)
2785        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
2786        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
2787        pretty_assertions::assert_eq!(
2788            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2789            BTreeMap::from_iter([
2790                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
2791                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
2792                (
2793                    Nibbles::from_nibbles([0x5, 0x0]),
2794                    SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
2795                ),
2796                (
2797                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
2798                    SparseNode::new_branch(0b1010.into())
2799                ),
2800                (
2801                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
2802                    SparseNode::new_leaf(Nibbles::default())
2803                ),
2804                (
2805                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
2806                    SparseNode::new_leaf(Nibbles::default())
2807                ),
2808                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
2809                (
2810                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
2811                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
2812                ),
2813                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
2814                (
2815                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
2816                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
2817                ),
2818                (
2819                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
2820                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
2821                )
2822            ])
2823        );
2824
2825        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), &provider).unwrap();
2826
2827        // Extension (Key = 5)
2828        // └── Branch (Mask = 1001)
2829        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
2830        //     └── 3 -> Branch (Mask = 0101)
2831        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
2832        //                └── 3 -> Branch (Mask = 1010)
2833        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
2834        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
2835        pretty_assertions::assert_eq!(
2836            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2837            BTreeMap::from_iter([
2838                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
2839                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
2840                (
2841                    Nibbles::from_nibbles([0x5, 0x0]),
2842                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
2843                ),
2844                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
2845                (
2846                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
2847                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
2848                ),
2849                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
2850                (
2851                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
2852                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
2853                ),
2854                (
2855                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
2856                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
2857                )
2858            ])
2859        );
2860
2861        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), &provider).unwrap();
2862
2863        // Extension (Key = 5)
2864        // └── Branch (Mask = 1001)
2865        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
2866        //     └── 3 -> Branch (Mask = 1010)
2867        //                ├── 0 -> Leaf (Key = 3302, Path = 53302)
2868        //                └── 2 -> Leaf (Key = 3320, Path = 53320)
2869        pretty_assertions::assert_eq!(
2870            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2871            BTreeMap::from_iter([
2872                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
2873                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
2874                (
2875                    Nibbles::from_nibbles([0x5, 0x0]),
2876                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
2877                ),
2878                (
2879                    Nibbles::from_nibbles([0x5, 0x3]),
2880                    SparseNode::new_ext(Nibbles::from_nibbles([0x3]))
2881                ),
2882                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
2883                (
2884                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
2885                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
2886                ),
2887                (
2888                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
2889                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
2890                )
2891            ])
2892        );
2893
2894        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &provider).unwrap();
2895
2896        // Extension (Key = 5)
2897        // └── Branch (Mask = 1001)
2898        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
2899        //     └── 3 -> Leaf (Key = 3302, Path = 53302)
2900        pretty_assertions::assert_eq!(
2901            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2902            BTreeMap::from_iter([
2903                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
2904                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
2905                (
2906                    Nibbles::from_nibbles([0x5, 0x0]),
2907                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
2908                ),
2909                (
2910                    Nibbles::from_nibbles([0x5, 0x3]),
2911                    SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x0, 0x2]))
2912                ),
2913            ])
2914        );
2915
2916        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), &provider).unwrap();
2917
2918        // Leaf (Key = 53302)
2919        pretty_assertions::assert_eq!(
2920            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2921            BTreeMap::from_iter([(
2922                Nibbles::default(),
2923                SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]))
2924            ),])
2925        );
2926
2927        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &provider).unwrap();
2928
2929        // Empty
2930        pretty_assertions::assert_eq!(
2931            sparse.nodes.clone().into_iter().collect::<BTreeMap<_, _>>(),
2932            BTreeMap::from_iter([(Nibbles::default(), SparseNode::Empty)])
2933        );
2934    }
2935
2936    #[test]
2937    fn sparse_trie_remove_leaf_blinded() {
2938        let leaf = LeafNode::new(
2939            Nibbles::default(),
2940            alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
2941        );
2942        let branch = TrieNode::Branch(BranchNode::new(
2943            vec![
2944                RlpNode::word_rlp(&B256::repeat_byte(1)),
2945                RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
2946            ],
2947            TrieMask::new(0b11),
2948        ));
2949
2950        let provider = DefaultTrieNodeProvider;
2951        let mut sparse = SerialSparseTrie::from_root(
2952            branch.clone(),
2953            TrieMasks { hash_mask: Some(TrieMask::new(0b01)), tree_mask: None },
2954            false,
2955        )
2956        .unwrap();
2957
2958        // Reveal a branch node and one of its children
2959        //
2960        // Branch (Mask = 11)
2961        // ├── 0 -> Hash (Path = 0)
2962        // └── 1 -> Leaf (Path = 1)
2963        sparse
2964            .reveal_node(
2965                Nibbles::default(),
2966                branch,
2967                TrieMasks { hash_mask: None, tree_mask: Some(TrieMask::new(0b01)) },
2968            )
2969            .unwrap();
2970        sparse
2971            .reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), TrieMasks::none())
2972            .unwrap();
2973
2974        // Removing a blinded leaf should result in an error
2975        assert_matches!(
2976            sparse.remove_leaf(&Nibbles::from_nibbles([0x0]), &provider).map_err(|e| e.into_kind()),
2977            Err(SparseTrieErrorKind::BlindedNode { path, hash }) if path == Nibbles::from_nibbles([0x0]) && hash == B256::repeat_byte(1)
2978        );
2979    }
2980
2981    #[test]
2982    fn sparse_trie_remove_leaf_non_existent() {
2983        let leaf = LeafNode::new(
2984            Nibbles::default(),
2985            alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
2986        );
2987        let branch = TrieNode::Branch(BranchNode::new(
2988            vec![
2989                RlpNode::word_rlp(&B256::repeat_byte(1)),
2990                RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
2991            ],
2992            TrieMask::new(0b11),
2993        ));
2994
2995        let provider = DefaultTrieNodeProvider;
2996        let mut sparse = SerialSparseTrie::from_root(
2997            branch.clone(),
2998            TrieMasks { hash_mask: Some(TrieMask::new(0b01)), tree_mask: None },
2999            false,
3000        )
3001        .unwrap();
3002
3003        // Reveal a branch node and one of its children
3004        //
3005        // Branch (Mask = 11)
3006        // ├── 0 -> Hash (Path = 0)
3007        // └── 1 -> Leaf (Path = 1)
3008        sparse
3009            .reveal_node(
3010                Nibbles::default(),
3011                branch,
3012                TrieMasks { hash_mask: None, tree_mask: Some(TrieMask::new(0b01)) },
3013            )
3014            .unwrap();
3015        sparse
3016            .reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), TrieMasks::none())
3017            .unwrap();
3018
3019        // Removing a non-existent leaf should be a noop
3020        let sparse_old = sparse.clone();
3021        assert_matches!(sparse.remove_leaf(&Nibbles::from_nibbles([0x2]), &provider), Ok(()));
3022        assert_eq!(sparse, sparse_old);
3023    }
3024
3025    #[test]
3026    fn sparse_trie_fuzz() {
3027        // Having only the first 3 nibbles set, we narrow down the range of keys
3028        // to 4096 different hashes. It allows us to generate collisions more likely
3029        // to test the sparse trie updates.
3030        const KEY_NIBBLES_LEN: usize = 3;
3031
3032        fn test(updates: Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)>) {
3033            {
3034                let mut state = BTreeMap::default();
3035                let default_provider = DefaultTrieNodeProvider;
3036                let provider_factory = create_test_provider_factory();
3037                let mut sparse = SerialSparseTrie::default().with_updates(true);
3038
3039                for (update, keys_to_delete) in updates {
3040                    // Insert state updates into the sparse trie and calculate the root
3041                    for (key, account) in update.clone() {
3042                        let account = account.into_trie_account(EMPTY_ROOT_HASH);
3043                        let mut account_rlp = Vec::new();
3044                        account.encode(&mut account_rlp);
3045                        sparse.update_leaf(key, account_rlp, &default_provider).unwrap();
3046                    }
3047                    // We need to clone the sparse trie, so that all updated branch nodes are
3048                    // preserved, and not only those that were changed after the last call to
3049                    // `root()`.
3050                    let mut updated_sparse = sparse.clone();
3051                    let sparse_root = updated_sparse.root();
3052                    let sparse_updates = updated_sparse.take_updates();
3053
3054                    // Insert state updates into the hash builder and calculate the root
3055                    state.extend(update);
3056                    let provider = provider_factory.provider().unwrap();
3057                    let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
3058                    let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
3059                        run_hash_builder(
3060                            state.clone(),
3061                            trie_cursor.account_trie_cursor().unwrap(),
3062                            Default::default(),
3063                            state.keys().copied(),
3064                        );
3065
3066                    // Extract account nodes before moving hash_builder_updates
3067                    let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
3068
3069                    // Write trie updates to the database
3070                    let provider_rw = provider_factory.provider_rw().unwrap();
3071                    provider_rw.write_trie_updates(hash_builder_updates).unwrap();
3072                    provider_rw.commit().unwrap();
3073
3074                    // Assert that the sparse trie root matches the hash builder root
3075                    assert_eq!(sparse_root, hash_builder_root);
3076                    // Assert that the sparse trie updates match the hash builder updates
3077                    pretty_assertions::assert_eq!(
3078                        BTreeMap::from_iter(sparse_updates.updated_nodes),
3079                        BTreeMap::from_iter(hash_builder_account_nodes)
3080                    );
3081                    // Assert that the sparse trie nodes match the hash builder proof nodes
3082                    assert_eq_sparse_trie_proof_nodes(&updated_sparse, hash_builder_proof_nodes);
3083
3084                    // Delete some keys from both the hash builder and the sparse trie and check
3085                    // that the sparse trie root still matches the hash builder root
3086                    for key in &keys_to_delete {
3087                        state.remove(key).unwrap();
3088                        sparse.remove_leaf(key, &default_provider).unwrap();
3089                    }
3090
3091                    // We need to clone the sparse trie, so that all updated branch nodes are
3092                    // preserved, and not only those that were changed after the last call to
3093                    // `root()`.
3094                    let mut updated_sparse = sparse.clone();
3095                    let sparse_root = updated_sparse.root();
3096                    let sparse_updates = updated_sparse.take_updates();
3097
3098                    let provider = provider_factory.provider().unwrap();
3099                    let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
3100                    let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
3101                        run_hash_builder(
3102                            state.clone(),
3103                            trie_cursor.account_trie_cursor().unwrap(),
3104                            keys_to_delete
3105                                .iter()
3106                                .map(|nibbles| B256::from_slice(&nibbles.pack()))
3107                                .collect(),
3108                            state.keys().copied(),
3109                        );
3110
3111                    // Extract account nodes before moving hash_builder_updates
3112                    let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
3113
3114                    // Write trie updates to the database
3115                    let provider_rw = provider_factory.provider_rw().unwrap();
3116                    provider_rw.write_trie_updates(hash_builder_updates).unwrap();
3117                    provider_rw.commit().unwrap();
3118
3119                    // Assert that the sparse trie root matches the hash builder root
3120                    assert_eq!(sparse_root, hash_builder_root);
3121                    // Assert that the sparse trie updates match the hash builder updates
3122                    pretty_assertions::assert_eq!(
3123                        BTreeMap::from_iter(sparse_updates.updated_nodes),
3124                        BTreeMap::from_iter(hash_builder_account_nodes)
3125                    );
3126                    // Assert that the sparse trie nodes match the hash builder proof nodes
3127                    assert_eq_sparse_trie_proof_nodes(&updated_sparse, hash_builder_proof_nodes);
3128                }
3129            }
3130        }
3131
3132        fn transform_updates(
3133            updates: Vec<BTreeMap<Nibbles, Account>>,
3134            mut rng: impl rand::Rng,
3135        ) -> Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)> {
3136            let mut keys = BTreeSet::new();
3137            updates
3138                .into_iter()
3139                .map(|update| {
3140                    keys.extend(update.keys().copied());
3141
3142                    let keys_to_delete_len = update.len() / 2;
3143                    let keys_to_delete = (0..keys_to_delete_len)
3144                        .map(|_| {
3145                            let key =
3146                                *rand::seq::IteratorRandom::choose(keys.iter(), &mut rng).unwrap();
3147                            keys.take(&key).unwrap()
3148                        })
3149                        .collect();
3150
3151                    (update, keys_to_delete)
3152                })
3153                .collect::<Vec<_>>()
3154        }
3155
3156        proptest!(ProptestConfig::with_cases(10), |(
3157            updates in proptest::collection::vec(
3158                proptest::collection::btree_map(
3159                    any_with::<Nibbles>(SizeRange::new(KEY_NIBBLES_LEN..=KEY_NIBBLES_LEN)).prop_map(pad_nibbles_right),
3160                    arb::<Account>(),
3161                    1..50,
3162                ),
3163                1..50,
3164            ).prop_perturb(transform_updates)
3165        )| {
3166            test(updates)
3167        });
3168    }
3169
3170    /// We have three leaves that share the same prefix: 0x00, 0x01 and 0x02. Hash builder trie has
3171    /// only nodes 0x00 and 0x02, and we have proofs for them. Node 0x01 is new and inserted in the
3172    /// sparse trie first.
3173    ///
3174    /// 1. Reveal the hash builder proof to leaf 0x00 in the sparse trie.
3175    /// 2. Insert leaf 0x01 into the sparse trie.
3176    /// 3. Reveal the hash builder proof to leaf 0x02 in the sparse trie.
3177    ///
3178    /// The hash builder proof to the leaf 0x02 didn't have the leaf 0x01 at the corresponding
3179    /// nibble of the branch node, so we need to adjust the branch node instead of fully
3180    /// replacing it.
3181    #[test]
3182    fn sparse_trie_reveal_node_1() {
3183        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00]));
3184        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01]));
3185        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x02]));
3186        let value = || Account::default();
3187        let value_encoded = || {
3188            let mut account_rlp = Vec::new();
3189            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
3190            account_rlp
3191        };
3192
3193        // Generate the proof for the root node and initialize the sparse trie with it
3194        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3195            run_hash_builder(
3196                [(key1(), value()), (key3(), value())],
3197                NoopAccountTrieCursor::default(),
3198                Default::default(),
3199                [Nibbles::default()],
3200            );
3201
3202        let provider = DefaultTrieNodeProvider;
3203        let mut sparse = SerialSparseTrie::from_root(
3204            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
3205            TrieMasks {
3206                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
3207                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
3208            },
3209            false,
3210        )
3211        .unwrap();
3212
3213        // Generate the proof for the first key and reveal it in the sparse trie
3214        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3215            run_hash_builder(
3216                [(key1(), value()), (key3(), value())],
3217                NoopAccountTrieCursor::default(),
3218                Default::default(),
3219                [key1()],
3220            );
3221        for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
3222            let hash_mask = branch_node_hash_masks.get(&path).copied();
3223            let tree_mask = branch_node_tree_masks.get(&path).copied();
3224            sparse
3225                .reveal_node(
3226                    path,
3227                    TrieNode::decode(&mut &node[..]).unwrap(),
3228                    TrieMasks { hash_mask, tree_mask },
3229                )
3230                .unwrap();
3231        }
3232
3233        // Check that the branch node exists with only two nibbles set
3234        assert_eq!(
3235            sparse.nodes.get(&Nibbles::default()),
3236            Some(&SparseNode::new_branch(0b101.into()))
3237        );
3238
3239        // Insert the leaf for the second key
3240        sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
3241
3242        // Check that the branch node was updated and another nibble was set
3243        assert_eq!(
3244            sparse.nodes.get(&Nibbles::default()),
3245            Some(&SparseNode::new_branch(0b111.into()))
3246        );
3247
3248        // Generate the proof for the third key and reveal it in the sparse trie
3249        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3250            run_hash_builder(
3251                [(key1(), value()), (key3(), value())],
3252                NoopAccountTrieCursor::default(),
3253                Default::default(),
3254                [key3()],
3255            );
3256        for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
3257            let hash_mask = branch_node_hash_masks.get(&path).copied();
3258            let tree_mask = branch_node_tree_masks.get(&path).copied();
3259            sparse
3260                .reveal_node(
3261                    path,
3262                    TrieNode::decode(&mut &node[..]).unwrap(),
3263                    TrieMasks { hash_mask, tree_mask },
3264                )
3265                .unwrap();
3266        }
3267
3268        // Check that nothing changed in the branch node
3269        assert_eq!(
3270            sparse.nodes.get(&Nibbles::default()),
3271            Some(&SparseNode::new_branch(0b111.into()))
3272        );
3273
3274        // Generate the nodes for the full trie with all three key using the hash builder, and
3275        // compare them to the sparse trie
3276        let (_, _, hash_builder_proof_nodes, _, _) = run_hash_builder(
3277            [(key1(), value()), (key2(), value()), (key3(), value())],
3278            NoopAccountTrieCursor::default(),
3279            Default::default(),
3280            [key1(), key2(), key3()],
3281        );
3282
3283        assert_eq_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
3284    }
3285
3286    /// We have three leaves: 0x0000, 0x0101, and 0x0102. Hash builder trie has all nodes, and we
3287    /// have proofs for them.
3288    ///
3289    /// 1. Reveal the hash builder proof to leaf 0x00 in the sparse trie.
3290    /// 2. Remove leaf 0x00 from the sparse trie (that will remove the branch node and create an
3291    ///    extension node with the key 0x0000).
3292    /// 3. Reveal the hash builder proof to leaf 0x0101 in the sparse trie.
3293    ///
3294    /// The hash builder proof to the leaf 0x0101 had a branch node in the path, but we turned it
3295    /// into an extension node, so it should ignore this node.
3296    #[test]
3297    fn sparse_trie_reveal_node_2() {
3298        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x00]));
3299        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x01]));
3300        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x02]));
3301        let value = || Account::default();
3302
3303        // Generate the proof for the root node and initialize the sparse trie with it
3304        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3305            run_hash_builder(
3306                [(key1(), value()), (key2(), value()), (key3(), value())],
3307                NoopAccountTrieCursor::default(),
3308                Default::default(),
3309                [Nibbles::default()],
3310            );
3311
3312        let provider = DefaultTrieNodeProvider;
3313        let mut sparse = SerialSparseTrie::from_root(
3314            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
3315            TrieMasks {
3316                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
3317                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
3318            },
3319            false,
3320        )
3321        .unwrap();
3322
3323        // Generate the proof for the children of the root branch node and reveal it in the sparse
3324        // trie
3325        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3326            run_hash_builder(
3327                [(key1(), value()), (key2(), value()), (key3(), value())],
3328                NoopAccountTrieCursor::default(),
3329                Default::default(),
3330                [key1(), Nibbles::from_nibbles_unchecked([0x01])],
3331            );
3332        for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
3333            let hash_mask = branch_node_hash_masks.get(&path).copied();
3334            let tree_mask = branch_node_tree_masks.get(&path).copied();
3335            sparse
3336                .reveal_node(
3337                    path,
3338                    TrieNode::decode(&mut &node[..]).unwrap(),
3339                    TrieMasks { hash_mask, tree_mask },
3340                )
3341                .unwrap();
3342        }
3343
3344        // Check that the branch node exists
3345        assert_eq!(
3346            sparse.nodes.get(&Nibbles::default()),
3347            Some(&SparseNode::new_branch(0b11.into()))
3348        );
3349
3350        // Remove the leaf for the first key
3351        sparse.remove_leaf(&key1(), &provider).unwrap();
3352
3353        // Check that the branch node was turned into an extension node
3354        assert_eq!(
3355            sparse.nodes.get(&Nibbles::default()),
3356            Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
3357        );
3358
3359        // Generate the proof for the third key and reveal it in the sparse trie
3360        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3361            run_hash_builder(
3362                [(key1(), value()), (key2(), value()), (key3(), value())],
3363                NoopAccountTrieCursor::default(),
3364                Default::default(),
3365                [key2()],
3366            );
3367        for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
3368            let hash_mask = branch_node_hash_masks.get(&path).copied();
3369            let tree_mask = branch_node_tree_masks.get(&path).copied();
3370            sparse
3371                .reveal_node(
3372                    path,
3373                    TrieNode::decode(&mut &node[..]).unwrap(),
3374                    TrieMasks { hash_mask, tree_mask },
3375                )
3376                .unwrap();
3377        }
3378
3379        // Check that nothing changed in the extension node
3380        assert_eq!(
3381            sparse.nodes.get(&Nibbles::default()),
3382            Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
3383        );
3384    }
3385
3386    /// We have two leaves that share the same prefix: 0x0001 and 0x0002, and a leaf with a
3387    /// different prefix: 0x0100. Hash builder trie has only the first two leaves, and we have
3388    /// proofs for them.
3389    ///
3390    /// 1. Insert the leaf 0x0100 into the sparse trie, and check that the root extension node was
3391    ///    turned into a branch node.
3392    /// 2. Reveal the leaf 0x0001 in the sparse trie, and check that the root branch node wasn't
3393    ///    overwritten with the extension node from the proof.
3394    #[test]
3395    fn sparse_trie_reveal_node_3() {
3396        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x01]));
3397        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x02]));
3398        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x00]));
3399        let value = || Account::default();
3400        let value_encoded = || {
3401            let mut account_rlp = Vec::new();
3402            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
3403            account_rlp
3404        };
3405
3406        // Generate the proof for the root node and initialize the sparse trie with it
3407        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3408            run_hash_builder(
3409                [(key1(), value()), (key2(), value())],
3410                NoopAccountTrieCursor::default(),
3411                Default::default(),
3412                [Nibbles::default()],
3413            );
3414
3415        let provider = DefaultTrieNodeProvider;
3416        let mut sparse = SerialSparseTrie::from_root(
3417            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
3418            TrieMasks {
3419                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
3420                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
3421            },
3422            false,
3423        )
3424        .unwrap();
3425
3426        // Check that the root extension node exists
3427        assert_matches!(
3428            sparse.nodes.get(&Nibbles::default()),
3429            Some(SparseNode::Extension { key, hash: None, store_in_db_trie: None }) if *key == Nibbles::from_nibbles([0x00])
3430        );
3431
3432        // Insert the leaf with a different prefix
3433        sparse.update_leaf(key3(), value_encoded(), &provider).unwrap();
3434
3435        // Check that the extension node was turned into a branch node
3436        assert_matches!(
3437            sparse.nodes.get(&Nibbles::default()),
3438            Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
3439        );
3440
3441        // Generate the proof for the first key and reveal it in the sparse trie
3442        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
3443            run_hash_builder(
3444                [(key1(), value()), (key2(), value())],
3445                NoopAccountTrieCursor::default(),
3446                Default::default(),
3447                [key1()],
3448            );
3449        for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
3450            let hash_mask = branch_node_hash_masks.get(&path).copied();
3451            let tree_mask = branch_node_tree_masks.get(&path).copied();
3452            sparse
3453                .reveal_node(
3454                    path,
3455                    TrieNode::decode(&mut &node[..]).unwrap(),
3456                    TrieMasks { hash_mask, tree_mask },
3457                )
3458                .unwrap();
3459        }
3460
3461        // Check that the branch node wasn't overwritten by the extension node in the proof
3462        assert_matches!(
3463            sparse.nodes.get(&Nibbles::default()),
3464            Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
3465        );
3466    }
3467
3468    #[test]
3469    fn sparse_trie_get_changed_nodes_at_depth() {
3470        let provider = DefaultTrieNodeProvider;
3471        let mut sparse = SerialSparseTrie::default();
3472
3473        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
3474
3475        // Extension (Key = 5) – Level 0
3476        // └── Branch (Mask = 1011) – Level 1
3477        //     ├── 0 -> Extension (Key = 23) – Level 2
3478        //     │        └── Branch (Mask = 0101) – Level 3
3479        //     │              ├── 1 -> Leaf (Key = 1, Path = 50231) – Level 4
3480        //     │              └── 3 -> Leaf (Key = 3, Path = 50233) – Level 4
3481        //     ├── 2 -> Leaf (Key = 013, Path = 52013) – Level 2
3482        //     └── 3 -> Branch (Mask = 0101) – Level 2
3483        //                ├── 1 -> Leaf (Key = 3102, Path = 53102) – Level 3
3484        //                └── 3 -> Branch (Mask = 1010) – Level 3
3485        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
3486        //                       └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
3487        sparse
3488            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
3489            .unwrap();
3490        sparse
3491            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
3492            .unwrap();
3493        sparse
3494            .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
3495            .unwrap();
3496        sparse
3497            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
3498            .unwrap();
3499        sparse
3500            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
3501            .unwrap();
3502        sparse
3503            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
3504            .unwrap();
3505
3506        assert_eq!(
3507            sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 0),
3508            (vec![(0, Nibbles::default())], PrefixSetMut::default())
3509        );
3510        assert_eq!(
3511            sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 1),
3512            (vec![(1, Nibbles::from_nibbles_unchecked([0x5]))], [Nibbles::default()].into())
3513        );
3514        assert_eq!(
3515            sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 2),
3516            (
3517                vec![
3518                    (2, Nibbles::from_nibbles_unchecked([0x5, 0x0])),
3519                    (2, Nibbles::from_nibbles_unchecked([0x5, 0x2])),
3520                    (2, Nibbles::from_nibbles_unchecked([0x5, 0x3]))
3521                ],
3522                [Nibbles::default(), Nibbles::from_nibbles_unchecked([0x5])].into()
3523            )
3524        );
3525        assert_eq!(
3526            sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 3),
3527            (
3528                vec![
3529                    (3, Nibbles::from_nibbles_unchecked([0x5, 0x0, 0x2, 0x3])),
3530                    (2, Nibbles::from_nibbles_unchecked([0x5, 0x2])),
3531                    (3, Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x1])),
3532                    (3, Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x3]))
3533                ],
3534                [
3535                    Nibbles::default(),
3536                    Nibbles::from_nibbles_unchecked([0x5]),
3537                    Nibbles::from_nibbles_unchecked([0x5, 0x0]),
3538                    Nibbles::from_nibbles_unchecked([0x5, 0x3])
3539                ]
3540                .into()
3541            )
3542        );
3543        assert_eq!(
3544            sparse.get_changed_nodes_at_depth(&mut PrefixSet::default(), 4),
3545            (
3546                vec![
3547                    (4, Nibbles::from_nibbles_unchecked([0x5, 0x0, 0x2, 0x3, 0x1])),
3548                    (4, Nibbles::from_nibbles_unchecked([0x5, 0x0, 0x2, 0x3, 0x3])),
3549                    (2, Nibbles::from_nibbles_unchecked([0x5, 0x2])),
3550                    (3, Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x1])),
3551                    (4, Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x3, 0x0])),
3552                    (4, Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x3, 0x2]))
3553                ],
3554                [
3555                    Nibbles::default(),
3556                    Nibbles::from_nibbles_unchecked([0x5]),
3557                    Nibbles::from_nibbles_unchecked([0x5, 0x0]),
3558                    Nibbles::from_nibbles_unchecked([0x5, 0x0, 0x2, 0x3]),
3559                    Nibbles::from_nibbles_unchecked([0x5, 0x3]),
3560                    Nibbles::from_nibbles_unchecked([0x5, 0x3, 0x3])
3561                ]
3562                .into()
3563            )
3564        );
3565    }
3566
3567    #[test]
3568    fn hash_builder_branch_hash_mask() {
3569        let key1 = || pad_nibbles_left(Nibbles::from_nibbles_unchecked([0x00]));
3570        let key2 = || pad_nibbles_left(Nibbles::from_nibbles_unchecked([0x01]));
3571        let value = || Account { bytecode_hash: Some(B256::repeat_byte(1)), ..Default::default() };
3572        let value_encoded = || {
3573            let mut account_rlp = Vec::new();
3574            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
3575            account_rlp
3576        };
3577
3578        let (hash_builder_root, hash_builder_updates, _, _, _) = run_hash_builder(
3579            [(key1(), value()), (key2(), value())],
3580            NoopAccountTrieCursor::default(),
3581            Default::default(),
3582            [Nibbles::default()],
3583        );
3584
3585        let provider = DefaultTrieNodeProvider;
3586        let mut sparse = SerialSparseTrie::default();
3587        sparse.update_leaf(key1(), value_encoded(), &provider).unwrap();
3588        sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
3589        let sparse_root = sparse.root();
3590        let sparse_updates = sparse.take_updates();
3591
3592        assert_eq!(sparse_root, hash_builder_root);
3593        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
3594    }
3595
3596    #[test]
3597    fn sparse_trie_wipe() {
3598        let provider = DefaultTrieNodeProvider;
3599        let mut sparse = SerialSparseTrie::default().with_updates(true);
3600
3601        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
3602
3603        // Extension (Key = 5) – Level 0
3604        // └── Branch (Mask = 1011) – Level 1
3605        //     ├── 0 -> Extension (Key = 23) – Level 2
3606        //     │        └── Branch (Mask = 0101) – Level 3
3607        //     │              ├── 1 -> Leaf (Key = 1, Path = 50231) – Level 4
3608        //     │              └── 3 -> Leaf (Key = 3, Path = 50233) – Level 4
3609        //     ├── 2 -> Leaf (Key = 013, Path = 52013) – Level 2
3610        //     └── 3 -> Branch (Mask = 0101) – Level 2
3611        //                ├── 1 -> Leaf (Key = 3102, Path = 53102) – Level 3
3612        //                └── 3 -> Branch (Mask = 1010) – Level 3
3613        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
3614        //                       └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
3615        sparse
3616            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
3617            .unwrap();
3618        sparse
3619            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
3620            .unwrap();
3621        sparse
3622            .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
3623            .unwrap();
3624        sparse
3625            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
3626            .unwrap();
3627        sparse
3628            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
3629            .unwrap();
3630        sparse
3631            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
3632            .unwrap();
3633
3634        sparse.wipe();
3635
3636        assert_matches!(
3637            &sparse.updates,
3638            Some(SparseTrieUpdates{ updated_nodes, removed_nodes, wiped })
3639            if updated_nodes.is_empty() && removed_nodes.is_empty() && *wiped
3640        );
3641        assert_eq!(sparse.root(), EMPTY_ROOT_HASH);
3642    }
3643
3644    #[test]
3645    fn sparse_trie_clear() {
3646        // tests that if we fill a sparse trie with some nodes and then clear it, it has the same
3647        // contents as an empty sparse trie
3648        let provider = DefaultTrieNodeProvider;
3649        let mut sparse = SerialSparseTrie::default();
3650        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
3651        sparse
3652            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
3653            .unwrap();
3654        sparse
3655            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
3656            .unwrap();
3657        sparse
3658            .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
3659            .unwrap();
3660        sparse
3661            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value, &provider)
3662            .unwrap();
3663
3664        sparse.clear();
3665
3666        let empty_trie = SerialSparseTrie::default();
3667        assert_eq!(empty_trie, sparse);
3668    }
3669
3670    #[test]
3671    fn sparse_trie_display() {
3672        let provider = DefaultTrieNodeProvider;
3673        let mut sparse = SerialSparseTrie::default();
3674
3675        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
3676
3677        // Extension (Key = 5) – Level 0
3678        // └── Branch (Mask = 1011) – Level 1
3679        //     ├── 0 -> Extension (Key = 23) – Level 2
3680        //     │        └── Branch (Mask = 0101) – Level 3
3681        //     │              ├── 1 -> Leaf (Key = 1, Path = 50231) – Level 4
3682        //     │              └── 3 -> Leaf (Key = 3, Path = 50233) – Level 4
3683        //     ├── 2 -> Leaf (Key = 013, Path = 52013) – Level 2
3684        //     └── 3 -> Branch (Mask = 0101) – Level 2
3685        //                ├── 1 -> Leaf (Key = 3102, Path = 53102) – Level 3
3686        //                └── 3 -> Branch (Mask = 1010) – Level 3
3687        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302) – Level 4
3688        //                       └── 2 -> Leaf (Key = 3320, Path = 53320) – Level 4
3689        sparse
3690            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone(), &provider)
3691            .unwrap();
3692        sparse
3693            .update_leaf(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone(), &provider)
3694            .unwrap();
3695        sparse
3696            .update_leaf(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone(), &provider)
3697            .unwrap();
3698        sparse
3699            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone(), &provider)
3700            .unwrap();
3701        sparse
3702            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone(), &provider)
3703            .unwrap();
3704        sparse
3705            .update_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value, &provider)
3706            .unwrap();
3707
3708        let normal_printed = format!("{sparse}");
3709        let expected = "\
3710Root -> Extension { key: Nibbles(0x5), hash: None, store_in_db_trie: None }
37115 -> Branch { state_mask: TrieMask(0000000000001101), hash: None, store_in_db_trie: None }
371250 -> Extension { key: Nibbles(0x23), hash: None, store_in_db_trie: None }
37135023 -> Branch { state_mask: TrieMask(0000000000001010), hash: None, store_in_db_trie: None }
371450231 -> Leaf { key: Nibbles(0x), hash: None }
371550233 -> Leaf { key: Nibbles(0x), hash: None }
371652013 -> Leaf { key: Nibbles(0x013), hash: None }
371753 -> Branch { state_mask: TrieMask(0000000000001010), hash: None, store_in_db_trie: None }
371853102 -> Leaf { key: Nibbles(0x02), hash: None }
3719533 -> Branch { state_mask: TrieMask(0000000000000101), hash: None, store_in_db_trie: None }
372053302 -> Leaf { key: Nibbles(0x2), hash: None }
372153320 -> Leaf { key: Nibbles(0x0), hash: None }
3722";
3723        assert_eq!(normal_printed, expected);
3724
3725        let alternate_printed = format!("{sparse:#}");
3726        let expected = "\
3727Root -> Extension { key: Nibbles(0x5), hash: None, store_in_db_trie: None }
3728    5 -> Branch { state_mask: TrieMask(0000000000001101), hash: None, store_in_db_trie: None }
3729        50 -> Extension { key: Nibbles(0x23), hash: None, store_in_db_trie: None }
3730            5023 -> Branch { state_mask: TrieMask(0000000000001010), hash: None, store_in_db_trie: None }
3731                50231 -> Leaf { key: Nibbles(0x), hash: None }
3732                50233 -> Leaf { key: Nibbles(0x), hash: None }
3733        52013 -> Leaf { key: Nibbles(0x013), hash: None }
3734        53 -> Branch { state_mask: TrieMask(0000000000001010), hash: None, store_in_db_trie: None }
3735            53102 -> Leaf { key: Nibbles(0x02), hash: None }
3736            533 -> Branch { state_mask: TrieMask(0000000000000101), hash: None, store_in_db_trie: None }
3737                53302 -> Leaf { key: Nibbles(0x2), hash: None }
3738                53320 -> Leaf { key: Nibbles(0x0), hash: None }
3739";
3740
3741        assert_eq!(alternate_printed, expected);
3742    }
3743}