reth_trie_sparse/
trie.rs

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