reth_trie_sparse_parallel/
trie.rs

1use crate::LowerSparseSubtrie;
2use alloc::borrow::Cow;
3use alloy_primitives::{
4    map::{Entry, HashMap},
5    B256,
6};
7use alloy_rlp::Decodable;
8use alloy_trie::{BranchNodeCompact, TrieMask, EMPTY_ROOT_HASH};
9use reth_execution_errors::{SparseTrieErrorKind, SparseTrieResult};
10use reth_trie_common::{
11    prefix_set::{PrefixSet, PrefixSetMut},
12    BranchNodeRef, ExtensionNodeRef, LeafNodeRef, Nibbles, RlpNode, TrieNode, CHILD_INDEX_RANGE,
13};
14use reth_trie_sparse::{
15    provider::{RevealedNode, TrieNodeProvider},
16    LeafLookup, LeafLookupError, RevealedSparseNode, RlpNodeStackItem, SparseNode, SparseNodeType,
17    SparseTrieInterface, SparseTrieUpdates, TrieMasks,
18};
19use smallvec::SmallVec;
20use std::{
21    cmp::{Ord, Ordering, PartialOrd},
22    sync::mpsc,
23};
24use tracing::{debug, instrument, trace};
25
26/// The maximum length of a path, in nibbles, which belongs to the upper subtrie of a
27/// [`ParallelSparseTrie`]. All longer paths belong to a lower subtrie.
28pub const UPPER_TRIE_MAX_DEPTH: usize = 2;
29
30/// Number of lower subtries which are managed by the [`ParallelSparseTrie`].
31pub const NUM_LOWER_SUBTRIES: usize = 16usize.pow(UPPER_TRIE_MAX_DEPTH as u32);
32
33/// Configuration for controlling when parallelism is enabled in [`ParallelSparseTrie`] operations.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
35pub struct ParallelismThresholds {
36    /// Minimum number of nodes to reveal before parallel processing is enabled.
37    /// When `reveal_nodes` has fewer nodes than this threshold, they will be processed serially.
38    pub min_revealed_nodes: usize,
39    /// Minimum number of changed keys (prefix set length) before parallel processing is enabled
40    /// for hash updates. When updating subtrie hashes with fewer changed keys than this threshold,
41    /// the updates will be processed serially.
42    pub min_updated_nodes: usize,
43}
44
45/// A revealed sparse trie with subtries that can be updated in parallel.
46///
47/// ## Structure
48///
49/// The trie is divided into two tiers for efficient parallel processing:
50/// - **Upper subtrie**: Contains nodes with paths shorter than [`UPPER_TRIE_MAX_DEPTH`]
51/// - **Lower subtries**: An array of [`NUM_LOWER_SUBTRIES`] subtries, each handling nodes with
52///   paths of at least [`UPPER_TRIE_MAX_DEPTH`] nibbles
53///
54/// Node placement is determined by path depth:
55/// - Paths with < [`UPPER_TRIE_MAX_DEPTH`] nibbles go to the upper subtrie
56/// - Paths with >= [`UPPER_TRIE_MAX_DEPTH`] nibbles go to lower subtries, indexed by their first
57///   [`UPPER_TRIE_MAX_DEPTH`] nibbles.
58///
59/// Each lower subtrie tracks its root via the `path` field, which represents the shortest path
60/// in that subtrie. This path will have at least [`UPPER_TRIE_MAX_DEPTH`] nibbles, but may be
61/// longer when an extension node in the upper trie "reaches into" the lower subtrie. For example,
62/// if the upper trie has an extension from `0x1` to `0x12345`, then the lower subtrie for prefix
63/// `0x12` will have its root at path `0x12345` rather than at `0x12`.
64///
65/// ## Node Revealing
66///
67/// The trie uses lazy loading to efficiently handle large state tries. Nodes can be:
68/// - **Blind nodes**: Stored as hashes ([`SparseNode::Hash`]), representing unloaded trie parts
69/// - **Revealed nodes**: Fully loaded nodes (Branch, Extension, Leaf) with complete structure
70///
71/// Note: An empty trie contains an `EmptyRoot` node at the root path, rather than no nodes at all.
72/// A trie with no nodes is blinded, its root may be `EmptyRoot` or some other node type.
73///
74/// Revealing is generally done using pre-loaded node data provided to via `reveal_nodes`. In
75/// certain cases, such as edge-cases when updating/removing leaves, nodes are revealed on-demand.
76///
77/// ## Leaf Operations
78///
79/// **Update**: When updating a leaf, the new value is stored in the appropriate subtrie's values
80/// map. If the leaf is new, the trie structure is updated by walking to the leaf from the root,
81/// creating necessary intermediate branch nodes.
82///
83/// **Removal**: Leaf removal may require parent node modifications. The algorithm walks up the
84/// trie, removing nodes that become empty and converting single-child branches to extensions.
85///
86/// During leaf operations the overall structure of the trie may change, causing nodes to be moved
87/// from the upper to lower trie or vice-versa.
88///
89/// The `prefix_set` is modified during both leaf updates and removals to track changed leaf paths.
90///
91/// ## Root Hash Calculation
92///
93/// Root hash computation follows a bottom-up approach:
94/// 1. Update hashes for all modified lower subtries (can be done in parallel)
95/// 2. Update hashes for the upper subtrie (which may reference lower subtrie hashes)
96/// 3. Calculate the final root hash from the upper subtrie's root node
97///
98/// The `prefix_set` tracks which paths have been modified, enabling incremental updates instead of
99/// recalculating the entire trie.
100///
101/// ## Invariants
102///
103/// - Each leaf entry in the `subtries` and `upper_trie` collection must have a corresponding entry
104///   in `values` collection. If the root node is a leaf, it must also have an entry in `values`.
105/// - All keys in `values` collection are full leaf paths.
106#[derive(Clone, PartialEq, Eq, Debug)]
107pub struct ParallelSparseTrie {
108    /// This contains the trie nodes for the upper part of the trie.
109    upper_subtrie: Box<SparseSubtrie>,
110    /// An array containing the subtries at the second level of the trie.
111    lower_subtries: [LowerSparseSubtrie; NUM_LOWER_SUBTRIES],
112    /// Set of prefixes (key paths) that have been marked as updated.
113    /// This is used to track which parts of the trie need to be recalculated.
114    prefix_set: PrefixSetMut,
115    /// Optional tracking of trie updates for later use.
116    updates: Option<SparseTrieUpdates>,
117    /// When a bit is set, the corresponding child subtree is stored in the database.
118    branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
119    /// When a bit is set, the corresponding child is stored as a hash in the database.
120    branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
121    /// Reusable buffer pool used for collecting [`SparseTrieUpdatesAction`]s during hash
122    /// computations.
123    update_actions_buffers: Vec<Vec<SparseTrieUpdatesAction>>,
124    /// Thresholds controlling when parallelism is enabled for different operations.
125    parallelism_thresholds: ParallelismThresholds,
126    /// Metrics for the parallel sparse trie.
127    #[cfg(feature = "metrics")]
128    metrics: crate::metrics::ParallelSparseTrieMetrics,
129}
130
131impl Default for ParallelSparseTrie {
132    fn default() -> Self {
133        Self {
134            upper_subtrie: Box::new(SparseSubtrie {
135                nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]),
136                ..Default::default()
137            }),
138            lower_subtries: [const { LowerSparseSubtrie::Blind(None) }; NUM_LOWER_SUBTRIES],
139            prefix_set: PrefixSetMut::default(),
140            updates: None,
141            branch_node_tree_masks: HashMap::default(),
142            branch_node_hash_masks: HashMap::default(),
143            update_actions_buffers: Vec::default(),
144            parallelism_thresholds: Default::default(),
145            #[cfg(feature = "metrics")]
146            metrics: Default::default(),
147        }
148    }
149}
150
151impl SparseTrieInterface for ParallelSparseTrie {
152    fn with_root(
153        mut self,
154        root: TrieNode,
155        masks: TrieMasks,
156        retain_updates: bool,
157    ) -> SparseTrieResult<Self> {
158        // A fresh/cleared `ParallelSparseTrie` has a `SparseNode::Empty` at its root in the upper
159        // subtrie. Delete that so we can reveal the new root node.
160        let path = Nibbles::default();
161        let _removed_root = self.upper_subtrie.nodes.remove(&path).expect("root node should exist");
162        debug_assert_eq!(_removed_root, SparseNode::Empty);
163
164        self = self.with_updates(retain_updates);
165
166        self.reveal_upper_node(Nibbles::default(), &root, masks)?;
167        Ok(self)
168    }
169
170    fn with_updates(mut self, retain_updates: bool) -> Self {
171        self.updates = retain_updates.then(Default::default);
172        self
173    }
174
175    fn reveal_nodes(&mut self, mut nodes: Vec<RevealedSparseNode>) -> SparseTrieResult<()> {
176        if nodes.is_empty() {
177            return Ok(())
178        }
179
180        // Sort nodes first by their subtrie, and secondarily by their path. This allows for
181        // grouping nodes by their subtrie using `chunk_by`.
182        nodes.sort_unstable_by(
183            |RevealedSparseNode { path: path_a, .. }, RevealedSparseNode { path: path_b, .. }| {
184                let subtrie_type_a = SparseSubtrieType::from_path(path_a);
185                let subtrie_type_b = SparseSubtrieType::from_path(path_b);
186                subtrie_type_a.cmp(&subtrie_type_b).then(path_a.cmp(path_b))
187            },
188        );
189
190        // Update the top-level branch node masks. This is simple and can't be done in parallel.
191        for RevealedSparseNode { path, masks, .. } in &nodes {
192            if let Some(tree_mask) = masks.tree_mask {
193                self.branch_node_tree_masks.insert(*path, tree_mask);
194            }
195            if let Some(hash_mask) = masks.hash_mask {
196                self.branch_node_hash_masks.insert(*path, hash_mask);
197            }
198        }
199
200        // Due to the sorting all upper subtrie nodes will be at the front of the slice. We split
201        // them off from the rest to be handled specially by
202        // `ParallelSparseTrie::reveal_upper_node`.
203        let num_upper_nodes = nodes
204            .iter()
205            .position(|n| !SparseSubtrieType::path_len_is_upper(n.path.len()))
206            .unwrap_or(nodes.len());
207
208        let upper_nodes = &nodes[..num_upper_nodes];
209        let lower_nodes = &nodes[num_upper_nodes..];
210
211        // Reserve the capacity of the upper subtrie's `nodes` HashMap before iterating, so we don't
212        // end up making many small capacity changes as we loop.
213        self.upper_subtrie.nodes.reserve(upper_nodes.len());
214        for node in upper_nodes {
215            self.reveal_upper_node(node.path, &node.node, node.masks)?;
216        }
217
218        if !self.is_reveal_parallelism_enabled(lower_nodes.len()) {
219            for node in lower_nodes {
220                if let Some(subtrie) = self.lower_subtrie_for_path_mut(&node.path) {
221                    subtrie.reveal_node(node.path, &node.node, node.masks)?;
222                } else {
223                    panic!("upper subtrie node {node:?} found amongst lower nodes");
224                }
225            }
226            return Ok(())
227        }
228
229        #[cfg(not(feature = "std"))]
230        unreachable!("nostd is checked by is_reveal_parallelism_enabled");
231
232        #[cfg(feature = "std")]
233        // Reveal lower subtrie nodes in parallel
234        {
235            use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
236
237            // Group the nodes by lower subtrie. This must be collected into a Vec in order for
238            // rayon's `zip` to be happy.
239            let node_groups: Vec<_> = lower_nodes
240                .chunk_by(|node_a, node_b| {
241                    SparseSubtrieType::from_path(&node_a.path) ==
242                        SparseSubtrieType::from_path(&node_b.path)
243                })
244                .collect();
245
246            // Take the lower subtries in the same order that the nodes were grouped into, so that
247            // the two can be zipped together. This also must be collected into a Vec for rayon's
248            // `zip` to be happy.
249            let lower_subtries: Vec<_> = node_groups
250                .iter()
251                .map(|nodes| {
252                    // NOTE: chunk_by won't produce empty groups
253                    let node = &nodes[0];
254                    let idx =
255                        SparseSubtrieType::from_path(&node.path).lower_index().unwrap_or_else(
256                            || panic!("upper subtrie node {node:?} found amongst lower nodes"),
257                        );
258                    // due to the nodes being sorted secondarily on their path, and chunk_by keeping
259                    // the first element of each group, the `path` here will necessarily be the
260                    // shortest path being revealed for each subtrie. Therefore we can reveal the
261                    // subtrie itself using this path and retain correct behavior.
262                    self.lower_subtries[idx].reveal(&node.path);
263                    (idx, self.lower_subtries[idx].take_revealed().expect("just revealed"))
264                })
265                .collect();
266
267            let (tx, rx) = mpsc::channel();
268
269            // Zip the lower subtries and their corresponding node groups, and reveal lower subtrie
270            // nodes in parallel
271            lower_subtries
272                .into_par_iter()
273                .zip(node_groups.into_par_iter())
274                .map(|((subtrie_idx, mut subtrie), nodes)| {
275                    // reserve space in the HashMap ahead of time; doing it on a node-by-node basis
276                    // can cause multiple re-allocations as the hashmap grows.
277                    subtrie.nodes.reserve(nodes.len());
278
279                    for node in nodes {
280                        // Reveal each node in the subtrie, returning early on any errors
281                        let res = subtrie.reveal_node(node.path, &node.node, node.masks);
282                        if res.is_err() {
283                            return (subtrie_idx, subtrie, res)
284                        }
285                    }
286                    (subtrie_idx, subtrie, Ok(()))
287                })
288                .for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
289
290            drop(tx);
291
292            // Take back all lower subtries which were sent to the rayon pool, collecting the last
293            // seen error in the process and returning that. If we don't fully drain the channel
294            // then we lose lower sparse tries, putting the whole ParallelSparseTrie in an
295            // inconsistent state.
296            let mut any_err = Ok(());
297            for (subtrie_idx, subtrie, res) in rx {
298                self.lower_subtries[subtrie_idx] = LowerSparseSubtrie::Revealed(subtrie);
299                if res.is_err() {
300                    any_err = res;
301                }
302            }
303
304            any_err
305        }
306    }
307
308    fn update_leaf<P: TrieNodeProvider>(
309        &mut self,
310        full_path: Nibbles,
311        value: Vec<u8>,
312        provider: P,
313    ) -> SparseTrieResult<()> {
314        self.prefix_set.insert(full_path);
315        let existing = self.upper_subtrie.inner.values.insert(full_path, value.clone());
316        if existing.is_some() {
317            // upper trie structure unchanged, return immediately
318            return Ok(())
319        }
320
321        let retain_updates = self.updates_enabled();
322
323        // Start at the root, traversing until we find either the node to update or a subtrie to
324        // update.
325        //
326        // We first traverse the upper subtrie for two levels, and moving any created nodes to a
327        // lower subtrie if necessary.
328        //
329        // We use `next` to keep track of the next node that we need to traverse to, and
330        // `new_nodes` to keep track of any nodes that were created during the traversal.
331        let mut new_nodes = Vec::new();
332        let mut next = Some(Nibbles::default());
333
334        // Traverse the upper subtrie to find the node to update or the subtrie to update.
335        //
336        // We stop when the next node to traverse would be in a lower subtrie, or if there are no
337        // more nodes to traverse.
338        while let Some(current) =
339            next.filter(|next| SparseSubtrieType::path_len_is_upper(next.len()))
340        {
341            // Traverse the next node, keeping track of any changed nodes and the next step in the
342            // trie
343            match self.upper_subtrie.update_next_node(current, &full_path, retain_updates)? {
344                LeafUpdateStep::Continue { next_node } => {
345                    next = Some(next_node);
346                }
347                LeafUpdateStep::Complete { inserted_nodes, reveal_path } => {
348                    new_nodes.extend(inserted_nodes);
349
350                    if let Some(reveal_path) = reveal_path {
351                        let subtrie = self.subtrie_for_path_mut(&reveal_path);
352                        if subtrie.nodes.get(&reveal_path).expect("node must exist").is_hash() {
353                            debug!(
354                                target: "trie::parallel_sparse",
355                                child_path = ?reveal_path,
356                                leaf_full_path = ?full_path,
357                                "Extension node child not revealed in update_leaf, falling back to db",
358                            );
359                            if let Some(RevealedNode { node, tree_mask, hash_mask }) =
360                                provider.trie_node(&reveal_path)?
361                            {
362                                let decoded = TrieNode::decode(&mut &node[..])?;
363                                trace!(
364                                    target: "trie::parallel_sparse",
365                                    ?reveal_path,
366                                    ?decoded,
367                                    ?tree_mask,
368                                    ?hash_mask,
369                                    "Revealing child (from upper)",
370                                );
371                                subtrie.reveal_node(
372                                    reveal_path,
373                                    &decoded,
374                                    TrieMasks { hash_mask, tree_mask },
375                                )?;
376                            } else {
377                                return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
378                                    path: reveal_path,
379                                }
380                                .into())
381                            }
382                        }
383                    }
384
385                    next = None;
386                }
387                LeafUpdateStep::NodeNotFound => {
388                    next = None;
389                }
390            }
391        }
392
393        // Move nodes from upper subtrie to lower subtries
394        for node_path in &new_nodes {
395            // Skip nodes that belong in the upper subtrie
396            if SparseSubtrieType::path_len_is_upper(node_path.len()) {
397                continue
398            }
399
400            let node =
401                self.upper_subtrie.nodes.remove(node_path).expect("node belongs to upper subtrie");
402
403            // If it's a leaf node, extract its value before getting mutable reference to subtrie.
404            let leaf_value = if let SparseNode::Leaf { key, .. } = &node {
405                let mut leaf_full_path = *node_path;
406                leaf_full_path.extend(key);
407                Some((
408                    leaf_full_path,
409                    self.upper_subtrie
410                        .inner
411                        .values
412                        .remove(&leaf_full_path)
413                        .expect("leaf nodes have associated values entries"),
414                ))
415            } else {
416                None
417            };
418
419            // Get or create the subtrie with the exact node path (not truncated to 2 nibbles).
420            let subtrie = self.subtrie_for_path_mut(node_path);
421
422            // Insert the leaf value if we have one
423            if let Some((leaf_full_path, value)) = leaf_value {
424                subtrie.inner.values.insert(leaf_full_path, value);
425            }
426
427            // Insert the node into the lower subtrie
428            subtrie.nodes.insert(*node_path, node);
429        }
430
431        // If we reached the max depth of the upper trie, we may have had more nodes to insert.
432        if let Some(next_path) = next.filter(|n| !SparseSubtrieType::path_len_is_upper(n.len())) {
433            // The value was inserted into the upper subtrie's `values` at the top of this method.
434            // At this point we know the value is not in the upper subtrie, and the call to
435            // `update_leaf` below will insert it into the lower subtrie. So remove it from the
436            // upper subtrie.
437            self.upper_subtrie.inner.values.remove(&full_path);
438
439            // Use subtrie_for_path to ensure the subtrie has the correct path.
440            //
441            // The next_path here represents where we need to continue traversal, which may
442            // be longer than 2 nibbles if we're following an extension node.
443            let subtrie = self.subtrie_for_path_mut(&next_path);
444
445            // Create an empty root at the subtrie path if the subtrie is empty
446            if subtrie.nodes.is_empty() {
447                subtrie.nodes.insert(subtrie.path, SparseNode::Empty);
448            }
449
450            // If we didn't update the target leaf, we need to call update_leaf on the subtrie
451            // to ensure that the leaf is updated correctly.
452            subtrie.update_leaf(full_path, value, provider, retain_updates)?;
453        }
454
455        Ok(())
456    }
457
458    fn remove_leaf<P: TrieNodeProvider>(
459        &mut self,
460        full_path: &Nibbles,
461        provider: P,
462    ) -> SparseTrieResult<()> {
463        // When removing a leaf node it's possibly necessary to modify its parent node, and possibly
464        // the parent's parent node. It is not ever necessary to descend further than that; once an
465        // extension node is hit it must terminate in a branch or the root, which won't need further
466        // updates. So the situation with maximum updates is:
467        //
468        // - Leaf
469        // - Branch with 2 children, one being this leaf
470        // - Extension
471        //
472        // ...which will result in just a leaf or extension, depending on what the branch's other
473        // child is.
474        //
475        // Therefore, first traverse the trie in order to find the leaf node and at most its parent
476        // and grandparent.
477
478        let leaf_path;
479        let leaf_subtrie;
480
481        let mut branch_parent_path: Option<Nibbles> = None;
482        let mut branch_parent_node: Option<SparseNode> = None;
483
484        let mut ext_grandparent_path: Option<Nibbles> = None;
485        let mut ext_grandparent_node: Option<SparseNode> = None;
486
487        let mut curr_path = Nibbles::new(); // start traversal from root
488        let mut curr_subtrie = self.upper_subtrie.as_mut();
489        let mut curr_subtrie_is_upper = true;
490
491        // List of node paths which need to have their hashes reset
492        let mut paths_to_reset_hashes = Vec::new();
493
494        loop {
495            let curr_node = curr_subtrie.nodes.get_mut(&curr_path).unwrap();
496
497            match Self::find_next_to_leaf(&curr_path, curr_node, full_path) {
498                FindNextToLeafOutcome::NotFound => return Ok(()), // leaf isn't in the trie
499                FindNextToLeafOutcome::BlindedNode(hash) => {
500                    return Err(SparseTrieErrorKind::BlindedNode { path: curr_path, hash }.into())
501                }
502                FindNextToLeafOutcome::Found => {
503                    // this node is the target leaf
504                    leaf_path = curr_path;
505                    leaf_subtrie = curr_subtrie;
506                    break;
507                }
508                FindNextToLeafOutcome::ContinueFrom(next_path) => {
509                    // Any branches/extensions along the path to the leaf will have their `hash`
510                    // field unset, as it will no longer be valid once the leaf is removed.
511                    match curr_node {
512                        SparseNode::Branch { hash, .. } => {
513                            if hash.is_some() {
514                                paths_to_reset_hashes
515                                    .push((SparseSubtrieType::from_path(&curr_path), curr_path));
516                            }
517
518                            // If there is already an extension leading into a branch, then that
519                            // extension is no longer relevant.
520                            match (&branch_parent_path, &ext_grandparent_path) {
521                                (Some(branch), Some(ext)) if branch.len() > ext.len() => {
522                                    ext_grandparent_path = None;
523                                    ext_grandparent_node = None;
524                                }
525                                _ => (),
526                            };
527                            branch_parent_path = Some(curr_path);
528                            branch_parent_node = Some(curr_node.clone());
529                        }
530                        SparseNode::Extension { hash, .. } => {
531                            if hash.is_some() {
532                                paths_to_reset_hashes
533                                    .push((SparseSubtrieType::from_path(&curr_path), curr_path));
534                            }
535
536                            // We can assume a new branch node will be found after the extension, so
537                            // there's no need to modify branch_parent_path/node even if it's
538                            // already set.
539                            ext_grandparent_path = Some(curr_path);
540                            ext_grandparent_node = Some(curr_node.clone());
541                        }
542                        SparseNode::Empty | SparseNode::Hash(_) | SparseNode::Leaf { .. } => {
543                            unreachable!(
544                                "find_next_to_leaf only continues to a branch or extension"
545                            )
546                        }
547                    }
548
549                    curr_path = next_path;
550
551                    // If we were previously looking at the upper trie, and the new path is in the
552                    // lower trie, we need to pull out a ref to the lower trie.
553                    if curr_subtrie_is_upper &&
554                        let SparseSubtrieType::Lower(idx) =
555                            SparseSubtrieType::from_path(&curr_path)
556                    {
557                        curr_subtrie = self.lower_subtries[idx]
558                            .as_revealed_mut()
559                            .expect("lower subtrie is revealed");
560                        curr_subtrie_is_upper = false;
561                    }
562                }
563            };
564        }
565
566        // We've traversed to the leaf and collected its ancestors as necessary. Remove the leaf
567        // from its SparseSubtrie and reset the hashes of the nodes along the path.
568        self.prefix_set.insert(*full_path);
569        leaf_subtrie.inner.values.remove(full_path);
570        for (subtrie_type, path) in paths_to_reset_hashes {
571            let node = match subtrie_type {
572                SparseSubtrieType::Upper => self.upper_subtrie.nodes.get_mut(&path),
573                SparseSubtrieType::Lower(idx) => self.lower_subtries[idx]
574                    .as_revealed_mut()
575                    .expect("lower subtrie is revealed")
576                    .nodes
577                    .get_mut(&path),
578            }
579            .expect("node exists");
580
581            match node {
582                SparseNode::Extension { hash, .. } | SparseNode::Branch { hash, .. } => {
583                    *hash = None
584                }
585                SparseNode::Empty | SparseNode::Hash(_) | SparseNode::Leaf { .. } => {
586                    unreachable!("only branch and extension node hashes can be reset")
587                }
588            }
589        }
590        self.remove_node(&leaf_path);
591
592        // If the leaf was at the root replace its node with the empty value. We can stop execution
593        // here, all remaining logic is related to the ancestors of the leaf.
594        if leaf_path.is_empty() {
595            self.upper_subtrie.nodes.insert(leaf_path, SparseNode::Empty);
596            return Ok(())
597        }
598
599        // If there is a parent branch node (very likely, unless the leaf is at the root) execute
600        // any required changes for that node, relative to the removed leaf.
601        if let (Some(branch_path), &Some(SparseNode::Branch { mut state_mask, .. })) =
602            (&branch_parent_path, &branch_parent_node)
603        {
604            let child_nibble = leaf_path.get_unchecked(branch_path.len());
605            state_mask.unset_bit(child_nibble);
606
607            let new_branch_node = if state_mask.count_bits() == 1 {
608                // If only one child is left set in the branch node, we need to collapse it. Get
609                // full path of the only child node left.
610                let remaining_child_path = {
611                    let mut p = *branch_path;
612                    p.push_unchecked(
613                        state_mask.first_set_bit_index().expect("state mask is not empty"),
614                    );
615                    p
616                };
617
618                trace!(
619                    target: "trie::parallel_sparse",
620                    ?leaf_path,
621                    ?branch_path,
622                    ?remaining_child_path,
623                    "Branch node has only one child",
624                );
625
626                // If the remaining child node is not yet revealed then we have to reveal it here,
627                // otherwise it's not possible to know how to collapse the branch.
628                let remaining_child_node = self.reveal_remaining_child_on_leaf_removal(
629                    provider,
630                    full_path,
631                    &remaining_child_path,
632                    true, // recurse_into_extension
633                )?;
634
635                let (new_branch_node, remove_child) = Self::branch_changes_on_leaf_removal(
636                    branch_path,
637                    &remaining_child_path,
638                    &remaining_child_node,
639                );
640
641                if remove_child {
642                    self.move_value_on_leaf_removal(
643                        branch_path,
644                        &new_branch_node,
645                        &remaining_child_path,
646                    );
647                    self.remove_node(&remaining_child_path);
648                }
649
650                if let Some(updates) = self.updates.as_mut() {
651                    updates.updated_nodes.remove(branch_path);
652                    updates.removed_nodes.insert(*branch_path);
653                }
654
655                new_branch_node
656            } else {
657                // If more than one child is left set in the branch, we just re-insert it with the
658                // updated state_mask.
659                SparseNode::new_branch(state_mask)
660            };
661
662            let branch_subtrie = self.subtrie_for_path_mut(branch_path);
663            branch_subtrie.nodes.insert(*branch_path, new_branch_node.clone());
664            branch_parent_node = Some(new_branch_node);
665        };
666
667        // If there is a grandparent extension node then there will necessarily be a parent branch
668        // node. Execute any required changes for the extension node, relative to the (possibly now
669        // replaced with a leaf or extension) branch node.
670        if let (Some(ext_path), Some(SparseNode::Extension { key: shortkey, .. })) =
671            (ext_grandparent_path, &ext_grandparent_node)
672        {
673            let ext_subtrie = self.subtrie_for_path_mut(&ext_path);
674            let branch_path = branch_parent_path.as_ref().unwrap();
675
676            if let Some(new_ext_node) = Self::extension_changes_on_leaf_removal(
677                &ext_path,
678                shortkey,
679                branch_path,
680                branch_parent_node.as_ref().unwrap(),
681            ) {
682                ext_subtrie.nodes.insert(ext_path, new_ext_node.clone());
683                self.move_value_on_leaf_removal(&ext_path, &new_ext_node, branch_path);
684                self.remove_node(branch_path);
685            }
686        }
687
688        Ok(())
689    }
690
691    #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
692    fn root(&mut self) -> B256 {
693        trace!(target: "trie::parallel_sparse", "Calculating trie root hash");
694
695        // Update all lower subtrie hashes
696        self.update_subtrie_hashes();
697
698        // Update hashes for the upper subtrie using our specialized function
699        // that can access both upper and lower subtrie nodes
700        let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
701        let root_rlp = self.update_upper_subtrie_hashes(&mut prefix_set);
702
703        // Return the root hash
704        root_rlp.as_hash().unwrap_or(EMPTY_ROOT_HASH)
705    }
706
707    #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
708    fn update_subtrie_hashes(&mut self) {
709        trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
710
711        // Take changed subtries according to the prefix set
712        let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
713        let num_changed_keys = prefix_set.len();
714        let (mut changed_subtries, unchanged_prefix_set) =
715            self.take_changed_lower_subtries(&mut prefix_set);
716
717        // update metrics
718        #[cfg(feature = "metrics")]
719        self.metrics.subtries_updated.record(changed_subtries.len() as f64);
720
721        // Update the prefix set with the keys that didn't have matching subtries
722        self.prefix_set = unchanged_prefix_set;
723
724        // Update subtrie hashes serially parallelism is not enabled
725        if !self.is_update_parallelism_enabled(num_changed_keys) {
726            for changed_subtrie in &mut changed_subtries {
727                changed_subtrie.subtrie.update_hashes(
728                    &mut changed_subtrie.prefix_set,
729                    &mut changed_subtrie.update_actions_buf,
730                    &self.branch_node_tree_masks,
731                    &self.branch_node_hash_masks,
732                );
733            }
734
735            self.insert_changed_subtries(changed_subtries);
736            return
737        }
738
739        #[cfg(not(feature = "std"))]
740        unreachable!("nostd is checked by is_update_parallelism_enabled");
741
742        #[cfg(feature = "std")]
743        // Update subtrie hashes in parallel
744        {
745            use rayon::iter::{IntoParallelIterator, ParallelIterator};
746            use tracing::debug_span;
747
748            let (tx, rx) = mpsc::channel();
749
750            let branch_node_tree_masks = &self.branch_node_tree_masks;
751            let branch_node_hash_masks = &self.branch_node_hash_masks;
752            let span = tracing::Span::current();
753            changed_subtries
754                .into_par_iter()
755                .map(|mut changed_subtrie| {
756                    let _enter = debug_span!(
757                        target: "trie::parallel_sparse",
758                        parent: span.clone(),
759                        "subtrie",
760                        index = changed_subtrie.index
761                    )
762                    .entered();
763
764                    #[cfg(feature = "metrics")]
765                    let start = std::time::Instant::now();
766                    changed_subtrie.subtrie.update_hashes(
767                        &mut changed_subtrie.prefix_set,
768                        &mut changed_subtrie.update_actions_buf,
769                        branch_node_tree_masks,
770                        branch_node_hash_masks,
771                    );
772                    #[cfg(feature = "metrics")]
773                    self.metrics.subtrie_hash_update_latency.record(start.elapsed());
774                    changed_subtrie
775                })
776                .for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
777
778            drop(tx);
779            self.insert_changed_subtries(rx);
780        }
781    }
782
783    fn get_leaf_value(&self, full_path: &Nibbles) -> Option<&Vec<u8>> {
784        self.subtrie_for_path(full_path).and_then(|subtrie| subtrie.inner.values.get(full_path))
785    }
786
787    fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates> {
788        self.updates.as_ref().map_or(Cow::Owned(SparseTrieUpdates::default()), Cow::Borrowed)
789    }
790
791    fn take_updates(&mut self) -> SparseTrieUpdates {
792        self.updates.take().unwrap_or_default()
793    }
794
795    fn wipe(&mut self) {
796        self.upper_subtrie.wipe();
797        self.lower_subtries = [const { LowerSparseSubtrie::Blind(None) }; NUM_LOWER_SUBTRIES];
798        self.prefix_set = PrefixSetMut::all();
799        self.updates = self.updates.is_some().then(SparseTrieUpdates::wiped);
800    }
801
802    fn clear(&mut self) {
803        self.upper_subtrie.clear();
804        self.upper_subtrie.nodes.insert(Nibbles::default(), SparseNode::Empty);
805        for subtrie in &mut self.lower_subtries {
806            subtrie.clear();
807        }
808        self.prefix_set.clear();
809        self.updates = None;
810        self.branch_node_tree_masks.clear();
811        self.branch_node_hash_masks.clear();
812        // `update_actions_buffers` doesn't need to be cleared; we want to reuse the Vecs it has
813        // buffered, and all of those are already inherently cleared when they get used.
814    }
815
816    fn find_leaf(
817        &self,
818        full_path: &Nibbles,
819        expected_value: Option<&Vec<u8>>,
820    ) -> Result<LeafLookup, LeafLookupError> {
821        // Inclusion proof
822        //
823        // First, do a quick check if the value exists in either the upper or lower subtrie's values
824        // map. We assume that if there exists a leaf node, then its value will be in the `values`
825        // map.
826        if let Some(actual_value) = std::iter::once(self.upper_subtrie.as_ref())
827            .chain(self.lower_subtrie_for_path(full_path))
828            .filter_map(|subtrie| subtrie.inner.values.get(full_path))
829            .next()
830        {
831            // We found the leaf, check if the value matches (if expected value was provided)
832            return expected_value
833                .is_none_or(|v| v == actual_value)
834                .then_some(LeafLookup::Exists)
835                .ok_or_else(|| LeafLookupError::ValueMismatch {
836                    path: *full_path,
837                    expected: expected_value.cloned(),
838                    actual: actual_value.clone(),
839                })
840        }
841
842        // If the value does not exist in the `values` map, then this means that the leaf either:
843        // - Does not exist in the trie
844        // - Is missing from the witness
845        // We traverse the trie to find the location where this leaf would have been, showing
846        // that it is not in the trie. Or we find a blinded node, showing that the witness is
847        // not complete.
848        let mut curr_path = Nibbles::new(); // start traversal from root
849        let mut curr_subtrie = self.upper_subtrie.as_ref();
850        let mut curr_subtrie_is_upper = true;
851
852        loop {
853            let curr_node = curr_subtrie.nodes.get(&curr_path).unwrap();
854
855            match Self::find_next_to_leaf(&curr_path, curr_node, full_path) {
856                FindNextToLeafOutcome::NotFound => return Ok(LeafLookup::NonExistent),
857                FindNextToLeafOutcome::BlindedNode(hash) => {
858                    // We hit a blinded node - cannot determine if leaf exists
859                    return Err(LeafLookupError::BlindedNode { path: curr_path, hash });
860                }
861                FindNextToLeafOutcome::Found => {
862                    panic!("target leaf {full_path:?} found at path {curr_path:?}, even though value wasn't in values hashmap");
863                }
864                FindNextToLeafOutcome::ContinueFrom(next_path) => {
865                    curr_path = next_path;
866                    // If we were previously looking at the upper trie, and the new path is in the
867                    // lower trie, we need to pull out a ref to the lower trie.
868                    if curr_subtrie_is_upper &&
869                        let Some(lower_subtrie) = self.lower_subtrie_for_path(&curr_path)
870                    {
871                        curr_subtrie = lower_subtrie;
872                        curr_subtrie_is_upper = false;
873                    }
874                }
875            }
876        }
877    }
878
879    fn shrink_nodes_to(&mut self, size: usize) {
880        // Distribute the capacity across upper and lower subtries
881        //
882        // Always include upper subtrie, plus any lower subtries
883        let total_subtries = 1 + NUM_LOWER_SUBTRIES;
884        let size_per_subtrie = size / total_subtries;
885
886        // Shrink the upper subtrie
887        self.upper_subtrie.shrink_nodes_to(size_per_subtrie);
888
889        // Shrink lower subtries (works for both revealed and blind with allocation)
890        for subtrie in &mut self.lower_subtries {
891            subtrie.shrink_nodes_to(size_per_subtrie);
892        }
893
894        // shrink masks maps
895        self.branch_node_hash_masks.shrink_to(size);
896        self.branch_node_tree_masks.shrink_to(size);
897    }
898
899    fn shrink_values_to(&mut self, size: usize) {
900        // Distribute the capacity across upper and lower subtries
901        //
902        // Always include upper subtrie, plus any lower subtries
903        let total_subtries = 1 + NUM_LOWER_SUBTRIES;
904        let size_per_subtrie = size / total_subtries;
905
906        // Shrink the upper subtrie
907        self.upper_subtrie.shrink_values_to(size_per_subtrie);
908
909        // Shrink lower subtries (works for both revealed and blind with allocation)
910        for subtrie in &mut self.lower_subtries {
911            subtrie.shrink_values_to(size_per_subtrie);
912        }
913    }
914}
915
916impl ParallelSparseTrie {
917    /// Sets the thresholds that control when parallelism is used during operations.
918    pub const fn with_parallelism_thresholds(mut self, thresholds: ParallelismThresholds) -> Self {
919        self.parallelism_thresholds = thresholds;
920        self
921    }
922
923    /// Returns true if retaining updates is enabled for the overall trie.
924    const fn updates_enabled(&self) -> bool {
925        self.updates.is_some()
926    }
927
928    /// Returns true if parallelism should be enabled for revealing the given number of nodes.
929    /// Will always return false in nostd builds.
930    const fn is_reveal_parallelism_enabled(&self, num_nodes: usize) -> bool {
931        #[cfg(not(feature = "std"))]
932        return false;
933
934        num_nodes >= self.parallelism_thresholds.min_revealed_nodes
935    }
936
937    /// Returns true if parallelism should be enabled for updating hashes with the given number
938    /// of changed keys. Will always return false in nostd builds.
939    const fn is_update_parallelism_enabled(&self, num_changed_keys: usize) -> bool {
940        #[cfg(not(feature = "std"))]
941        return false;
942
943        num_changed_keys >= self.parallelism_thresholds.min_updated_nodes
944    }
945
946    /// Creates a new revealed sparse trie from the given root node.
947    ///
948    /// This function initializes the internal structures and then reveals the root.
949    /// It is a convenient method to create a trie when you already have the root node available.
950    ///
951    /// # Arguments
952    ///
953    /// * `root` - The root node of the trie
954    /// * `masks` - Trie masks for root branch node
955    /// * `retain_updates` - Whether to track updates
956    ///
957    /// # Returns
958    ///
959    /// Self if successful, or an error if revealing fails.
960    pub fn from_root(
961        root: TrieNode,
962        masks: TrieMasks,
963        retain_updates: bool,
964    ) -> SparseTrieResult<Self> {
965        Self::default().with_root(root, masks, retain_updates)
966    }
967
968    /// Returns a reference to the lower `SparseSubtrie` for the given path, or None if the
969    /// path belongs to the upper trie, or if the lower subtrie for the path doesn't exist or is
970    /// blinded.
971    fn lower_subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
972        match SparseSubtrieType::from_path(path) {
973            SparseSubtrieType::Upper => None,
974            SparseSubtrieType::Lower(idx) => self.lower_subtries[idx].as_revealed_ref(),
975        }
976    }
977
978    /// Returns a mutable reference to the lower `SparseSubtrie` for the given path, or None if the
979    /// path belongs to the upper trie.
980    ///
981    /// This method will create/reveal a new lower subtrie for the given path if one isn't already.
982    /// If one does exist, but its path field is longer than the given path, then the field will be
983    /// set to the given path.
984    fn lower_subtrie_for_path_mut(&mut self, path: &Nibbles) -> Option<&mut SparseSubtrie> {
985        match SparseSubtrieType::from_path(path) {
986            SparseSubtrieType::Upper => None,
987            SparseSubtrieType::Lower(idx) => {
988                self.lower_subtries[idx].reveal(path);
989                Some(self.lower_subtries[idx].as_revealed_mut().expect("just revealed"))
990            }
991        }
992    }
993
994    /// Returns a reference to either the lower or upper `SparseSubtrie` for the given path,
995    /// depending on the path's length.
996    ///
997    /// Returns `None` if a lower subtrie does not exist for the given path.
998    fn subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
999        // We can't just call `lower_subtrie_for_path` and return `upper_subtrie` if it returns
1000        // None, because Rust complains about double mutable borrowing `self`.
1001        if SparseSubtrieType::path_len_is_upper(path.len()) {
1002            Some(&self.upper_subtrie)
1003        } else {
1004            self.lower_subtrie_for_path(path)
1005        }
1006    }
1007
1008    /// Returns a mutable reference to either the lower or upper `SparseSubtrie` for the given path,
1009    /// depending on the path's length.
1010    ///
1011    /// This method will create/reveal a new lower subtrie for the given path if one isn't already.
1012    /// If one does exist, but its path field is longer than the given path, then the field will be
1013    /// set to the given path.
1014    fn subtrie_for_path_mut(&mut self, path: &Nibbles) -> &mut SparseSubtrie {
1015        // We can't just call `lower_subtrie_for_path` and return `upper_subtrie` if it returns
1016        // None, because Rust complains about double mutable borrowing `self`.
1017        if SparseSubtrieType::path_len_is_upper(path.len()) {
1018            &mut self.upper_subtrie
1019        } else {
1020            self.lower_subtrie_for_path_mut(path).unwrap()
1021        }
1022    }
1023
1024    /// Returns the next node in the traversal path from the given path towards the leaf for the
1025    /// given full leaf path, or an error if any node along the traversal path is not revealed.
1026    ///
1027    ///
1028    /// ## Panics
1029    ///
1030    /// If `from_path` is not a prefix of `leaf_full_path`.
1031    fn find_next_to_leaf(
1032        from_path: &Nibbles,
1033        from_node: &SparseNode,
1034        leaf_full_path: &Nibbles,
1035    ) -> FindNextToLeafOutcome {
1036        debug_assert!(leaf_full_path.len() >= from_path.len());
1037        debug_assert!(leaf_full_path.starts_with(from_path));
1038
1039        match from_node {
1040            // If empty node is found it means the subtrie doesn't have any nodes in it, let alone
1041            // the target leaf.
1042            SparseNode::Empty => FindNextToLeafOutcome::NotFound,
1043            SparseNode::Hash(hash) => FindNextToLeafOutcome::BlindedNode(*hash),
1044            SparseNode::Leaf { key, .. } => {
1045                let mut found_full_path = *from_path;
1046                found_full_path.extend(key);
1047
1048                if &found_full_path == leaf_full_path {
1049                    return FindNextToLeafOutcome::Found
1050                }
1051                FindNextToLeafOutcome::NotFound
1052            }
1053            SparseNode::Extension { key, .. } => {
1054                if leaf_full_path.len() == from_path.len() {
1055                    return FindNextToLeafOutcome::NotFound
1056                }
1057
1058                let mut child_path = *from_path;
1059                child_path.extend(key);
1060
1061                if !leaf_full_path.starts_with(&child_path) {
1062                    return FindNextToLeafOutcome::NotFound
1063                }
1064                FindNextToLeafOutcome::ContinueFrom(child_path)
1065            }
1066            SparseNode::Branch { state_mask, .. } => {
1067                if leaf_full_path.len() == from_path.len() {
1068                    return FindNextToLeafOutcome::NotFound
1069                }
1070
1071                let nibble = leaf_full_path.get_unchecked(from_path.len());
1072                if !state_mask.is_bit_set(nibble) {
1073                    return FindNextToLeafOutcome::NotFound
1074                }
1075
1076                let mut child_path = *from_path;
1077                child_path.push_unchecked(nibble);
1078
1079                FindNextToLeafOutcome::ContinueFrom(child_path)
1080            }
1081        }
1082    }
1083
1084    /// Called when a child node has collapsed into its parent as part of `remove_leaf`. If the
1085    /// new parent node is a leaf, then the previous child also was, and if the previous child was
1086    /// on a lower subtrie while the parent is on an upper then the leaf value needs to be moved to
1087    /// the upper.
1088    fn move_value_on_leaf_removal(
1089        &mut self,
1090        parent_path: &Nibbles,
1091        new_parent_node: &SparseNode,
1092        prev_child_path: &Nibbles,
1093    ) {
1094        // If the parent path isn't in the upper then it doesn't matter what the new node is,
1095        // there's no situation where a leaf value needs to be moved.
1096        if SparseSubtrieType::from_path(parent_path).lower_index().is_some() {
1097            return;
1098        }
1099
1100        if let SparseNode::Leaf { key, .. } = new_parent_node {
1101            let Some(prev_child_subtrie) = self.lower_subtrie_for_path_mut(prev_child_path) else {
1102                return;
1103            };
1104
1105            let mut leaf_full_path = *parent_path;
1106            leaf_full_path.extend(key);
1107
1108            let val = prev_child_subtrie.inner.values.remove(&leaf_full_path).expect("ParallelSparseTrie is in an inconsistent state, expected value on subtrie which wasn't found");
1109            self.upper_subtrie.inner.values.insert(leaf_full_path, val);
1110        }
1111    }
1112
1113    /// Used by `remove_leaf` to ensure that when a node is removed from a lower subtrie that any
1114    /// externalities are handled. These can include:
1115    /// - Removing the lower subtrie completely, if it is now empty.
1116    /// - Updating the `path` field of the lower subtrie to indicate that its root node has changed.
1117    ///
1118    /// This method assumes that the caller will deal with putting all other nodes in the trie into
1119    /// a consistent state after the removal of this one.
1120    ///
1121    /// ## Panics
1122    ///
1123    /// - If the removed node was not a leaf or extension.
1124    fn remove_node(&mut self, path: &Nibbles) {
1125        let subtrie = self.subtrie_for_path_mut(path);
1126        let node = subtrie.nodes.remove(path);
1127
1128        let Some(idx) = SparseSubtrieType::from_path(path).lower_index() else {
1129            // When removing a node from the upper trie there's nothing special we need to do to fix
1130            // its path field; the upper trie's path is always empty.
1131            return;
1132        };
1133
1134        match node {
1135            Some(SparseNode::Leaf { .. }) => {
1136                // If the leaf was the final node in its lower subtrie then we can blind the
1137                // subtrie, effectively marking it as empty.
1138                if subtrie.nodes.is_empty() {
1139                    self.lower_subtries[idx].clear();
1140                }
1141            }
1142            Some(SparseNode::Extension { key, .. }) => {
1143                // If the removed extension was the root node of a lower subtrie then the lower
1144                // subtrie's `path` needs to be updated to be whatever node the extension used to
1145                // point to.
1146                if &subtrie.path == path {
1147                    subtrie.path.extend(&key);
1148                }
1149            }
1150            _ => panic!("Expected to remove a leaf or extension, but removed {node:?}"),
1151        }
1152    }
1153
1154    /// Given the path to a parent branch node and a child node which is the sole remaining child on
1155    /// that branch after removing a leaf, returns a node to replace the parent branch node and a
1156    /// boolean indicating if the child should be deleted.
1157    ///
1158    /// ## Panics
1159    ///
1160    /// - If either parent or child node is not already revealed.
1161    /// - If parent's path is not a prefix of the child's path.
1162    fn branch_changes_on_leaf_removal(
1163        parent_path: &Nibbles,
1164        remaining_child_path: &Nibbles,
1165        remaining_child_node: &SparseNode,
1166    ) -> (SparseNode, bool) {
1167        debug_assert!(remaining_child_path.len() > parent_path.len());
1168        debug_assert!(remaining_child_path.starts_with(parent_path));
1169
1170        let remaining_child_nibble = remaining_child_path.get_unchecked(parent_path.len());
1171
1172        // If we swap the branch node out either an extension or leaf, depending on
1173        // what its remaining child is.
1174        match remaining_child_node {
1175            SparseNode::Empty | SparseNode::Hash(_) => {
1176                panic!("remaining child must have been revealed already")
1177            }
1178            // If the only child is a leaf node, we downgrade the branch node into a
1179            // leaf node, prepending the nibble to the key, and delete the old
1180            // child.
1181            SparseNode::Leaf { key, .. } => {
1182                let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1183                new_key.extend(key);
1184                (SparseNode::new_leaf(new_key), true)
1185            }
1186            // If the only child node is an extension node, we downgrade the branch
1187            // node into an even longer extension node, prepending the nibble to the
1188            // key, and delete the old child.
1189            SparseNode::Extension { key, .. } => {
1190                let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1191                new_key.extend(key);
1192                (SparseNode::new_ext(new_key), true)
1193            }
1194            // If the only child is a branch node, we downgrade the current branch
1195            // node into a one-nibble extension node.
1196            SparseNode::Branch { .. } => (
1197                SparseNode::new_ext(Nibbles::from_nibbles_unchecked([remaining_child_nibble])),
1198                false,
1199            ),
1200        }
1201    }
1202
1203    /// Given the path to a parent extension and its key, and a child node (not necessarily on this
1204    /// subtrie), returns an optional replacement parent node. If a replacement is returned then the
1205    /// child node should be deleted.
1206    ///
1207    /// ## Panics
1208    ///
1209    /// - If either parent or child node is not already revealed.
1210    /// - If parent's path is not a prefix of the child's path.
1211    fn extension_changes_on_leaf_removal(
1212        parent_path: &Nibbles,
1213        parent_key: &Nibbles,
1214        child_path: &Nibbles,
1215        child: &SparseNode,
1216    ) -> Option<SparseNode> {
1217        debug_assert!(child_path.len() > parent_path.len());
1218        debug_assert!(child_path.starts_with(parent_path));
1219
1220        // If the parent node is an extension node, we need to look at its child to see
1221        // if we need to merge it.
1222        match child {
1223            SparseNode::Empty | SparseNode::Hash(_) => {
1224                panic!("child must be revealed")
1225            }
1226            // For a leaf node, we collapse the extension node into a leaf node,
1227            // extending the key. While it's impossible to encounter an extension node
1228            // followed by a leaf node in a complete trie, it's possible here because we
1229            // could have downgraded the extension node's child into a leaf node from a
1230            // branch in a previous call to `branch_changes_on_leaf_removal`.
1231            SparseNode::Leaf { key, .. } => {
1232                let mut new_key = *parent_key;
1233                new_key.extend(key);
1234                Some(SparseNode::new_leaf(new_key))
1235            }
1236            // Similar to the leaf node, for an extension node, we collapse them into one
1237            // extension node, extending the key.
1238            SparseNode::Extension { key, .. } => {
1239                let mut new_key = *parent_key;
1240                new_key.extend(key);
1241                Some(SparseNode::new_ext(new_key))
1242            }
1243            // For a branch node, we just leave the extension node as-is.
1244            SparseNode::Branch { .. } => None,
1245        }
1246    }
1247
1248    /// Called when a leaf is removed on a branch which has only one other remaining child. That
1249    /// child must be revealed in order to properly collapse the branch.
1250    ///
1251    /// If `recurse_into_extension` is true, and the remaining child is an extension node, then its
1252    /// child will be ensured to be revealed as well.
1253    ///
1254    /// ## Returns
1255    ///
1256    /// The node of the remaining child, whether it was already revealed or not.
1257    fn reveal_remaining_child_on_leaf_removal<P: TrieNodeProvider>(
1258        &mut self,
1259        provider: P,
1260        full_path: &Nibbles, // only needed for logs
1261        remaining_child_path: &Nibbles,
1262        recurse_into_extension: bool,
1263    ) -> SparseTrieResult<SparseNode> {
1264        let remaining_child_subtrie = self.subtrie_for_path_mut(remaining_child_path);
1265
1266        let remaining_child_node =
1267            match remaining_child_subtrie.nodes.get(remaining_child_path).unwrap() {
1268                SparseNode::Hash(_) => {
1269                    debug!(
1270                        target: "trie::parallel_sparse",
1271                        child_path = ?remaining_child_path,
1272                        leaf_full_path = ?full_path,
1273                        "Node child not revealed in remove_leaf, falling back to db",
1274                    );
1275                    if let Some(RevealedNode { node, tree_mask, hash_mask }) =
1276                        provider.trie_node(remaining_child_path)?
1277                    {
1278                        let decoded = TrieNode::decode(&mut &node[..])?;
1279                        trace!(
1280                            target: "trie::parallel_sparse",
1281                            ?remaining_child_path,
1282                            ?decoded,
1283                            ?tree_mask,
1284                            ?hash_mask,
1285                            "Revealing remaining blinded branch child"
1286                        );
1287                        remaining_child_subtrie.reveal_node(
1288                            *remaining_child_path,
1289                            &decoded,
1290                            TrieMasks { hash_mask, tree_mask },
1291                        )?;
1292                        remaining_child_subtrie.nodes.get(remaining_child_path).unwrap().clone()
1293                    } else {
1294                        return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
1295                            path: *remaining_child_path,
1296                        }
1297                        .into())
1298                    }
1299                }
1300                node => node.clone(),
1301            };
1302
1303        // If `recurse_into_extension` is true, and the remaining child is an extension node, then
1304        // its child will be ensured to be revealed as well. This is required for generation of
1305        // trie updates; without revealing the grandchild branch it's not always possible to know
1306        // if the tree mask bit should be set for the child extension on its parent branch.
1307        if let SparseNode::Extension { key, .. } = &remaining_child_node &&
1308            recurse_into_extension
1309        {
1310            let mut remaining_grandchild_path = *remaining_child_path;
1311            remaining_grandchild_path.extend(key);
1312
1313            trace!(
1314                target: "trie::parallel_sparse",
1315                remaining_grandchild_path = ?remaining_grandchild_path,
1316                child_path = ?remaining_child_path,
1317                leaf_full_path = ?full_path,
1318                "Revealing child of extension node, which is the last remaining child of the branch"
1319            );
1320
1321            self.reveal_remaining_child_on_leaf_removal(
1322                provider,
1323                full_path,
1324                &remaining_grandchild_path,
1325                false, // recurse_into_extension
1326            )?;
1327        }
1328
1329        Ok(remaining_child_node)
1330    }
1331
1332    /// Drains any [`SparseTrieUpdatesAction`]s from the given subtrie, and applies each action to
1333    /// the given `updates` set. If the given set is None then this is a no-op.
1334    #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
1335    fn apply_subtrie_update_actions(
1336        &mut self,
1337        update_actions: impl Iterator<Item = SparseTrieUpdatesAction>,
1338    ) {
1339        if let Some(updates) = self.updates.as_mut() {
1340            for action in update_actions {
1341                match action {
1342                    SparseTrieUpdatesAction::InsertRemoved(path) => {
1343                        updates.updated_nodes.remove(&path);
1344                        updates.removed_nodes.insert(path);
1345                    }
1346                    SparseTrieUpdatesAction::RemoveUpdated(path) => {
1347                        updates.updated_nodes.remove(&path);
1348                    }
1349                    SparseTrieUpdatesAction::InsertUpdated(path, branch_node) => {
1350                        updates.updated_nodes.insert(path, branch_node);
1351                    }
1352                }
1353            }
1354        };
1355    }
1356
1357    /// Updates hashes for the upper subtrie, using nodes from both upper and lower subtries.
1358    #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, ret)]
1359    fn update_upper_subtrie_hashes(&mut self, prefix_set: &mut PrefixSet) -> RlpNode {
1360        trace!(target: "trie::parallel_sparse", "Updating upper subtrie hashes");
1361
1362        debug_assert!(self.upper_subtrie.inner.buffers.path_stack.is_empty());
1363        self.upper_subtrie.inner.buffers.path_stack.push(RlpNodePathStackItem {
1364            path: Nibbles::default(), // Start from root
1365            is_in_prefix_set: None,
1366        });
1367
1368        #[cfg(feature = "metrics")]
1369        let start = std::time::Instant::now();
1370
1371        let mut update_actions_buf =
1372            self.updates_enabled().then(|| self.update_actions_buffers.pop().unwrap_or_default());
1373
1374        while let Some(stack_item) = self.upper_subtrie.inner.buffers.path_stack.pop() {
1375            let path = stack_item.path;
1376            let node = if path.len() < UPPER_TRIE_MAX_DEPTH {
1377                self.upper_subtrie.nodes.get_mut(&path).expect("upper subtrie node must exist")
1378            } else {
1379                let index = path_subtrie_index_unchecked(&path);
1380                let node = self.lower_subtries[index]
1381                    .as_revealed_mut()
1382                    .expect("lower subtrie must exist")
1383                    .nodes
1384                    .get_mut(&path)
1385                    .expect("lower subtrie node must exist");
1386                // Lower subtrie root node hashes must be computed before updating upper subtrie
1387                // hashes
1388                debug_assert!(
1389                    node.hash().is_some(),
1390                    "Lower subtrie root node at path {path:?} has no hash"
1391                );
1392                node
1393            };
1394
1395            // Calculate the RLP node for the current node using upper subtrie
1396            self.upper_subtrie.inner.rlp_node(
1397                prefix_set,
1398                &mut update_actions_buf,
1399                stack_item,
1400                node,
1401                &self.branch_node_tree_masks,
1402                &self.branch_node_hash_masks,
1403            );
1404        }
1405
1406        // If there were any branch node updates as a result of calculating the RLP node for the
1407        // upper trie then apply them to the top-level set.
1408        if let Some(mut update_actions_buf) = update_actions_buf {
1409            self.apply_subtrie_update_actions(
1410                #[allow(clippy::iter_with_drain)]
1411                update_actions_buf.drain(..),
1412            );
1413            self.update_actions_buffers.push(update_actions_buf);
1414        }
1415
1416        #[cfg(feature = "metrics")]
1417        self.metrics.subtrie_upper_hash_latency.record(start.elapsed());
1418
1419        debug_assert_eq!(self.upper_subtrie.inner.buffers.rlp_node_stack.len(), 1);
1420        self.upper_subtrie.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
1421    }
1422
1423    /// Returns:
1424    /// 1. List of lower [subtries](SparseSubtrie) that have changed according to the provided
1425    ///    [prefix set](PrefixSet). See documentation of [`ChangedSubtrie`] for more details. Lower
1426    ///    subtries whose root node is missing a hash will also be returned; this is required to
1427    ///    handle cases where extensions/leafs get shortened and therefore moved from the upper to a
1428    ///    lower subtrie.
1429    /// 2. Prefix set of keys that do not belong to any lower subtrie.
1430    ///
1431    /// This method helps optimize hash recalculations by identifying which specific
1432    /// lower subtries need to be updated. Each lower subtrie can then be updated in parallel.
1433    ///
1434    /// IMPORTANT: The method removes the subtries from `lower_subtries`, and the caller is
1435    /// responsible for returning them back into the array.
1436    #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(prefix_set_len = prefix_set.len()))]
1437    fn take_changed_lower_subtries(
1438        &mut self,
1439        prefix_set: &mut PrefixSet,
1440    ) -> (Vec<ChangedSubtrie>, PrefixSetMut) {
1441        // Fast-path: If the prefix set is empty then no subtries can have been changed. Just return
1442        // empty values.
1443        if prefix_set.is_empty() && !prefix_set.all() {
1444            return Default::default();
1445        }
1446
1447        // Clone the prefix set to iterate over its keys. Cloning is cheap, it's just an Arc.
1448        let prefix_set_clone = prefix_set.clone();
1449        let mut prefix_set_iter = prefix_set_clone.into_iter().copied().peekable();
1450        let mut changed_subtries = Vec::new();
1451        let mut unchanged_prefix_set = PrefixSetMut::default();
1452        let updates_enabled = self.updates_enabled();
1453
1454        for (index, subtrie) in self.lower_subtries.iter_mut().enumerate() {
1455            if let Some(subtrie) = subtrie.take_revealed_if(|subtrie| {
1456                prefix_set.contains(&subtrie.path) ||
1457                    subtrie.nodes.get(&subtrie.path).is_some_and(|n| n.hash().is_none())
1458            }) {
1459                let prefix_set = if prefix_set.all() {
1460                    unchanged_prefix_set = PrefixSetMut::all();
1461                    PrefixSetMut::all()
1462                } else {
1463                    // Take those keys from the original prefix set that start with the subtrie path
1464                    //
1465                    // Subtries are stored in the order of their paths, so we can use the same
1466                    // prefix set iterator.
1467                    let mut new_prefix_set = Vec::new();
1468                    while let Some(key) = prefix_set_iter.peek() {
1469                        if key.starts_with(&subtrie.path) {
1470                            // If the key starts with the subtrie path, add it to the new prefix set
1471                            new_prefix_set.push(prefix_set_iter.next().unwrap());
1472                        } else if new_prefix_set.is_empty() && key < &subtrie.path {
1473                            // If we didn't yet have any keys that belong to this subtrie, and the
1474                            // current key is still less than the subtrie path, add it to the
1475                            // unchanged prefix set
1476                            unchanged_prefix_set.insert(prefix_set_iter.next().unwrap());
1477                        } else {
1478                            // If we're past the subtrie path, we're done with this subtrie. Do not
1479                            // advance the iterator, the next key will be processed either by the
1480                            // next subtrie or inserted into the unchanged prefix set.
1481                            break
1482                        }
1483                    }
1484                    PrefixSetMut::from(new_prefix_set)
1485                }
1486                .freeze();
1487
1488                // We need the full path of root node of the lower subtrie to the unchanged prefix
1489                // set, so that we don't skip it when calculating hashes for the upper subtrie.
1490                match subtrie.nodes.get(&subtrie.path) {
1491                    Some(SparseNode::Extension { key, .. } | SparseNode::Leaf { key, .. }) => {
1492                        unchanged_prefix_set.insert(subtrie.path.join(key));
1493                    }
1494                    Some(SparseNode::Branch { .. }) => {
1495                        unchanged_prefix_set.insert(subtrie.path);
1496                    }
1497                    _ => {}
1498                }
1499
1500                let update_actions_buf =
1501                    updates_enabled.then(|| self.update_actions_buffers.pop().unwrap_or_default());
1502
1503                changed_subtries.push(ChangedSubtrie {
1504                    index,
1505                    subtrie,
1506                    prefix_set,
1507                    update_actions_buf,
1508                });
1509            }
1510        }
1511
1512        // Extend the unchanged prefix set with the remaining keys that are not part of any subtries
1513        unchanged_prefix_set.extend_keys(prefix_set_iter);
1514
1515        (changed_subtries, unchanged_prefix_set)
1516    }
1517
1518    /// Returns an iterator over all nodes in the trie in no particular order.
1519    #[cfg(test)]
1520    fn all_nodes(&self) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
1521        let mut nodes = vec![];
1522        for subtrie in self.lower_subtries.iter().filter_map(LowerSparseSubtrie::as_revealed_ref) {
1523            nodes.extend(subtrie.nodes.iter())
1524        }
1525        nodes.extend(self.upper_subtrie.nodes.iter());
1526        nodes
1527    }
1528
1529    /// Reveals a trie node in the upper trie if it has not been revealed before. When revealing
1530    /// branch/extension nodes this may recurse into a lower trie to reveal a child.
1531    ///
1532    /// This function decodes a trie node and inserts it into the trie structure. It handles
1533    /// different node types (leaf, extension, branch) by appropriately adding them to the trie and
1534    /// recursively revealing their children.
1535    ///
1536    /// # Arguments
1537    ///
1538    /// * `path` - The path where the node should be revealed
1539    /// * `node` - The trie node to reveal
1540    /// * `masks` - Trie masks for branch nodes
1541    ///
1542    /// # Returns
1543    ///
1544    /// `Ok(())` if successful, or an error if the node was not revealed.
1545    fn reveal_upper_node(
1546        &mut self,
1547        path: Nibbles,
1548        node: &TrieNode,
1549        masks: TrieMasks,
1550    ) -> SparseTrieResult<()> {
1551        // If there is no subtrie for the path it means the path is UPPER_TRIE_MAX_DEPTH or less
1552        // nibbles, and so belongs to the upper trie.
1553        self.upper_subtrie.reveal_node(path, node, masks)?;
1554
1555        // The previous upper_trie.reveal_node call will not have revealed any child nodes via
1556        // reveal_node_or_hash if the child node would be found on a lower subtrie. We handle that
1557        // here by manually checking the specific cases where this could happen, and calling
1558        // reveal_node_or_hash for each.
1559        match node {
1560            TrieNode::Branch(branch) => {
1561                // If a branch is at the cutoff level of the trie then it will be in the upper trie,
1562                // but all of its children will be in a lower trie. Check if a child node would be
1563                // in the lower subtrie, and reveal accordingly.
1564                if !SparseSubtrieType::path_len_is_upper(path.len() + 1) {
1565                    let mut stack_ptr = branch.as_ref().first_child_index();
1566                    for idx in CHILD_INDEX_RANGE {
1567                        if branch.state_mask.is_bit_set(idx) {
1568                            let mut child_path = path;
1569                            child_path.push_unchecked(idx);
1570                            self.lower_subtrie_for_path_mut(&child_path)
1571                                .expect("child_path must have a lower subtrie")
1572                                .reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?;
1573                            stack_ptr += 1;
1574                        }
1575                    }
1576                }
1577            }
1578            TrieNode::Extension(ext) => {
1579                let mut child_path = path;
1580                child_path.extend(&ext.key);
1581                if let Some(subtrie) = self.lower_subtrie_for_path_mut(&child_path) {
1582                    subtrie.reveal_node_or_hash(child_path, &ext.child)?;
1583                }
1584            }
1585            TrieNode::EmptyRoot | TrieNode::Leaf(_) => (),
1586        }
1587
1588        Ok(())
1589    }
1590
1591    /// Return updated subtries back to the trie after executing any actions required on the
1592    /// top-level `SparseTrieUpdates`.
1593    #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
1594    fn insert_changed_subtries(
1595        &mut self,
1596        changed_subtries: impl IntoIterator<Item = ChangedSubtrie>,
1597    ) {
1598        for ChangedSubtrie { index, subtrie, update_actions_buf, .. } in changed_subtries {
1599            if let Some(mut update_actions_buf) = update_actions_buf {
1600                self.apply_subtrie_update_actions(
1601                    #[allow(clippy::iter_with_drain)]
1602                    update_actions_buf.drain(..),
1603                );
1604                self.update_actions_buffers.push(update_actions_buf);
1605            }
1606
1607            self.lower_subtries[index] = LowerSparseSubtrie::Revealed(subtrie);
1608        }
1609    }
1610}
1611
1612/// This is a subtrie of the [`ParallelSparseTrie`] that contains a map from path to sparse trie
1613/// nodes.
1614#[derive(Clone, PartialEq, Eq, Debug, Default)]
1615pub struct SparseSubtrie {
1616    /// The root path of this subtrie.
1617    ///
1618    /// This is the _full_ path to this subtrie, meaning it includes the first
1619    /// [`UPPER_TRIE_MAX_DEPTH`] nibbles that we also use for indexing subtries in the
1620    /// [`ParallelSparseTrie`].
1621    ///
1622    /// There should be a node for this path in `nodes` map.
1623    pub(crate) path: Nibbles,
1624    /// The map from paths to sparse trie nodes within this subtrie.
1625    nodes: HashMap<Nibbles, SparseNode>,
1626    /// Subset of fields for mutable access while `nodes` field is also being mutably borrowed.
1627    inner: SparseSubtrieInner,
1628}
1629
1630/// Returned by the `find_next_to_leaf` method to indicate either that the leaf has been found,
1631/// traversal should be continued from the given path, or the leaf is not in the trie.
1632enum FindNextToLeafOutcome {
1633    /// `Found` indicates that the leaf was found at the given path.
1634    Found,
1635    /// `ContinueFrom` indicates that traversal should continue from the given path.
1636    ContinueFrom(Nibbles),
1637    /// `NotFound` indicates that there is no way to traverse to the leaf, as it is not in the
1638    /// trie.
1639    NotFound,
1640    /// `BlindedNode` indicates that the node is blinded with the contained hash and cannot be
1641    /// traversed.
1642    BlindedNode(B256),
1643}
1644
1645impl SparseSubtrie {
1646    /// Creates a new empty subtrie with the specified root path.
1647    pub(crate) fn new(path: Nibbles) -> Self {
1648        Self { path, ..Default::default() }
1649    }
1650
1651    /// Returns true if this subtrie has any nodes, false otherwise.
1652    pub(crate) fn is_empty(&self) -> bool {
1653        self.nodes.is_empty()
1654    }
1655
1656    /// Returns true if the current path and its child are both found in the same level.
1657    fn is_child_same_level(current_path: &Nibbles, child_path: &Nibbles) -> bool {
1658        let current_level = core::mem::discriminant(&SparseSubtrieType::from_path(current_path));
1659        let child_level = core::mem::discriminant(&SparseSubtrieType::from_path(child_path));
1660        current_level == child_level
1661    }
1662
1663    /// Updates or inserts a leaf node at the specified key path with the provided RLP-encoded
1664    /// value.
1665    ///
1666    /// If the leaf did not previously exist, this method adjusts the trie structure by inserting
1667    /// new leaf nodes, splitting branch nodes, or collapsing extension nodes as needed.
1668    ///
1669    /// # Returns
1670    ///
1671    /// Returns the `Ok` if the update is successful.
1672    ///
1673    /// Note: If an update requires revealing a blinded node, an error is returned if the blinded
1674    /// provider returns an error.
1675    pub fn update_leaf(
1676        &mut self,
1677        full_path: Nibbles,
1678        value: Vec<u8>,
1679        provider: impl TrieNodeProvider,
1680        retain_updates: bool,
1681    ) -> SparseTrieResult<()> {
1682        debug_assert!(full_path.starts_with(&self.path));
1683        let existing = self.inner.values.insert(full_path, value);
1684        if existing.is_some() {
1685            // trie structure unchanged, return immediately
1686            return Ok(())
1687        }
1688
1689        // Here we are starting at the root of the subtrie, and traversing from there.
1690        let mut current = Some(self.path);
1691        while let Some(current_path) = current {
1692            match self.update_next_node(current_path, &full_path, retain_updates)? {
1693                LeafUpdateStep::Continue { next_node } => {
1694                    current = Some(next_node);
1695                }
1696                LeafUpdateStep::Complete { reveal_path, .. } => {
1697                    if let Some(reveal_path) = reveal_path &&
1698                        self.nodes.get(&reveal_path).expect("node must exist").is_hash()
1699                    {
1700                        debug!(
1701                            target: "trie::parallel_sparse",
1702                            child_path = ?reveal_path,
1703                            leaf_full_path = ?full_path,
1704                            "Extension node child not revealed in update_leaf, falling back to db",
1705                        );
1706                        if let Some(RevealedNode { node, tree_mask, hash_mask }) =
1707                            provider.trie_node(&reveal_path)?
1708                        {
1709                            let decoded = TrieNode::decode(&mut &node[..])?;
1710                            trace!(
1711                                target: "trie::parallel_sparse",
1712                                ?reveal_path,
1713                                ?decoded,
1714                                ?tree_mask,
1715                                ?hash_mask,
1716                                "Revealing child (from lower)",
1717                            );
1718                            self.reveal_node(
1719                                reveal_path,
1720                                &decoded,
1721                                TrieMasks { hash_mask, tree_mask },
1722                            )?;
1723                        } else {
1724                            return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
1725                                path: reveal_path,
1726                            }
1727                            .into())
1728                        }
1729                    }
1730
1731                    current = None;
1732                }
1733                LeafUpdateStep::NodeNotFound => {
1734                    current = None;
1735                }
1736            }
1737        }
1738
1739        Ok(())
1740    }
1741
1742    /// Processes the current node, returning what to do next in the leaf update process.
1743    ///
1744    /// This will add or update any nodes in the trie as necessary.
1745    ///
1746    /// Returns a `LeafUpdateStep` containing the next node to process (if any) and
1747    /// the paths of nodes that were inserted during this step.
1748    fn update_next_node(
1749        &mut self,
1750        mut current: Nibbles,
1751        path: &Nibbles,
1752        retain_updates: bool,
1753    ) -> SparseTrieResult<LeafUpdateStep> {
1754        debug_assert!(path.starts_with(&self.path));
1755        debug_assert!(current.starts_with(&self.path));
1756        debug_assert!(path.starts_with(&current));
1757        let Some(node) = self.nodes.get_mut(&current) else {
1758            return Ok(LeafUpdateStep::NodeNotFound);
1759        };
1760        match node {
1761            SparseNode::Empty => {
1762                // We need to insert the node with a different path and key depending on the path of
1763                // the subtrie.
1764                let path = path.slice(self.path.len()..);
1765                *node = SparseNode::new_leaf(path);
1766                Ok(LeafUpdateStep::complete_with_insertions(vec![current], None))
1767            }
1768            SparseNode::Hash(hash) => {
1769                Err(SparseTrieErrorKind::BlindedNode { path: current, hash: *hash }.into())
1770            }
1771            SparseNode::Leaf { key: current_key, .. } => {
1772                current.extend(current_key);
1773
1774                // this leaf is being updated
1775                debug_assert!(
1776                    &current != path,
1777                    "we already checked leaf presence in the beginning"
1778                );
1779
1780                // find the common prefix
1781                let common = current.common_prefix_length(path);
1782
1783                // update existing node
1784                let new_ext_key = current.slice(current.len() - current_key.len()..common);
1785                *node = SparseNode::new_ext(new_ext_key);
1786
1787                // create a branch node and corresponding leaves
1788                self.nodes.reserve(3);
1789                let branch_path = current.slice(..common);
1790                let new_leaf_path = path.slice(..=common);
1791                let existing_leaf_path = current.slice(..=common);
1792
1793                self.nodes.insert(
1794                    branch_path,
1795                    SparseNode::new_split_branch(
1796                        current.get_unchecked(common),
1797                        path.get_unchecked(common),
1798                    ),
1799                );
1800                self.nodes.insert(new_leaf_path, SparseNode::new_leaf(path.slice(common + 1..)));
1801                self.nodes
1802                    .insert(existing_leaf_path, SparseNode::new_leaf(current.slice(common + 1..)));
1803
1804                Ok(LeafUpdateStep::complete_with_insertions(
1805                    vec![branch_path, new_leaf_path, existing_leaf_path],
1806                    None,
1807                ))
1808            }
1809            SparseNode::Extension { key, .. } => {
1810                current.extend(key);
1811
1812                if !path.starts_with(&current) {
1813                    // find the common prefix
1814                    let common = current.common_prefix_length(path);
1815                    *key = current.slice(current.len() - key.len()..common);
1816
1817                    // If branch node updates retention is enabled, we need to query the
1818                    // extension node child to later set the hash mask for a parent branch node
1819                    // correctly.
1820                    let reveal_path = retain_updates.then_some(current);
1821
1822                    // create state mask for new branch node
1823                    // NOTE: this might overwrite the current extension node
1824                    self.nodes.reserve(3);
1825                    let branch_path = current.slice(..common);
1826                    let new_leaf_path = path.slice(..=common);
1827                    let branch = SparseNode::new_split_branch(
1828                        current.get_unchecked(common),
1829                        path.get_unchecked(common),
1830                    );
1831
1832                    self.nodes.insert(branch_path, branch);
1833
1834                    // create new leaf
1835                    let new_leaf = SparseNode::new_leaf(path.slice(common + 1..));
1836                    self.nodes.insert(new_leaf_path, new_leaf);
1837
1838                    let mut inserted_nodes = vec![branch_path, new_leaf_path];
1839
1840                    // recreate extension to previous child if needed
1841                    let key = current.slice(common + 1..);
1842                    if !key.is_empty() {
1843                        let ext_path = current.slice(..=common);
1844                        self.nodes.insert(ext_path, SparseNode::new_ext(key));
1845                        inserted_nodes.push(ext_path);
1846                    }
1847
1848                    return Ok(LeafUpdateStep::complete_with_insertions(inserted_nodes, reveal_path))
1849                }
1850
1851                Ok(LeafUpdateStep::continue_with(current))
1852            }
1853            SparseNode::Branch { state_mask, .. } => {
1854                let nibble = path.get_unchecked(current.len());
1855                current.push_unchecked(nibble);
1856                if !state_mask.is_bit_set(nibble) {
1857                    state_mask.set_bit(nibble);
1858                    let new_leaf = SparseNode::new_leaf(path.slice(current.len()..));
1859                    self.nodes.insert(current, new_leaf);
1860                    return Ok(LeafUpdateStep::complete_with_insertions(vec![current], None))
1861                }
1862
1863                // If the nibble is set, we can continue traversing the branch.
1864                Ok(LeafUpdateStep::continue_with(current))
1865            }
1866        }
1867    }
1868
1869    /// Internal implementation of the method of the same name on `ParallelSparseTrie`.
1870    fn reveal_node(
1871        &mut self,
1872        path: Nibbles,
1873        node: &TrieNode,
1874        masks: TrieMasks,
1875    ) -> SparseTrieResult<()> {
1876        debug_assert!(path.starts_with(&self.path));
1877
1878        // If the node is already revealed and it's not a hash node, do nothing.
1879        if self.nodes.get(&path).is_some_and(|node| !node.is_hash()) {
1880            return Ok(())
1881        }
1882
1883        match node {
1884            TrieNode::EmptyRoot => {
1885                // For an empty root, ensure that we are at the root path, and at the upper subtrie.
1886                debug_assert!(path.is_empty());
1887                debug_assert!(self.path.is_empty());
1888                self.nodes.insert(path, SparseNode::Empty);
1889            }
1890            TrieNode::Branch(branch) => {
1891                // For a branch node, iterate over all potential children
1892                let mut stack_ptr = branch.as_ref().first_child_index();
1893                for idx in CHILD_INDEX_RANGE {
1894                    if branch.state_mask.is_bit_set(idx) {
1895                        let mut child_path = path;
1896                        child_path.push_unchecked(idx);
1897                        if Self::is_child_same_level(&path, &child_path) {
1898                            // Reveal each child node or hash it has, but only if the child is on
1899                            // the same level as the parent.
1900                            self.reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?;
1901                        }
1902                        stack_ptr += 1;
1903                    }
1904                }
1905                // Update the branch node entry in the nodes map, handling cases where a blinded
1906                // node is now replaced with a revealed node.
1907                match self.nodes.entry(path) {
1908                    Entry::Occupied(mut entry) => match entry.get() {
1909                        // Replace a hash node with a fully revealed branch node.
1910                        SparseNode::Hash(hash) => {
1911                            entry.insert(SparseNode::Branch {
1912                                state_mask: branch.state_mask,
1913                                // Memoize the hash of a previously blinded node in a new branch
1914                                // node.
1915                                hash: Some(*hash),
1916                                store_in_db_trie: Some(
1917                                    masks.hash_mask.is_some_and(|mask| !mask.is_empty()) ||
1918                                        masks.tree_mask.is_some_and(|mask| !mask.is_empty()),
1919                                ),
1920                            });
1921                        }
1922                        // Branch node already exists, or an extension node was placed where a
1923                        // branch node was before.
1924                        SparseNode::Branch { .. } | SparseNode::Extension { .. } => {}
1925                        // All other node types can't be handled.
1926                        node @ (SparseNode::Empty | SparseNode::Leaf { .. }) => {
1927                            return Err(SparseTrieErrorKind::Reveal {
1928                                path: *entry.key(),
1929                                node: Box::new(node.clone()),
1930                            }
1931                            .into())
1932                        }
1933                    },
1934                    Entry::Vacant(entry) => {
1935                        entry.insert(SparseNode::new_branch(branch.state_mask));
1936                    }
1937                }
1938            }
1939            TrieNode::Extension(ext) => match self.nodes.entry(path) {
1940                Entry::Occupied(mut entry) => match entry.get() {
1941                    // Replace a hash node with a revealed extension node.
1942                    SparseNode::Hash(hash) => {
1943                        let mut child_path = *entry.key();
1944                        child_path.extend(&ext.key);
1945                        entry.insert(SparseNode::Extension {
1946                            key: ext.key,
1947                            // Memoize the hash of a previously blinded node in a new extension
1948                            // node.
1949                            hash: Some(*hash),
1950                            store_in_db_trie: None,
1951                        });
1952                        if Self::is_child_same_level(&path, &child_path) {
1953                            self.reveal_node_or_hash(child_path, &ext.child)?;
1954                        }
1955                    }
1956                    // Extension node already exists, or an extension node was placed where a branch
1957                    // node was before.
1958                    SparseNode::Extension { .. } | SparseNode::Branch { .. } => {}
1959                    // All other node types can't be handled.
1960                    node @ (SparseNode::Empty | SparseNode::Leaf { .. }) => {
1961                        return Err(SparseTrieErrorKind::Reveal {
1962                            path: *entry.key(),
1963                            node: Box::new(node.clone()),
1964                        }
1965                        .into())
1966                    }
1967                },
1968                Entry::Vacant(entry) => {
1969                    let mut child_path = *entry.key();
1970                    child_path.extend(&ext.key);
1971                    entry.insert(SparseNode::new_ext(ext.key));
1972                    if Self::is_child_same_level(&path, &child_path) {
1973                        self.reveal_node_or_hash(child_path, &ext.child)?;
1974                    }
1975                }
1976            },
1977            TrieNode::Leaf(leaf) => match self.nodes.entry(path) {
1978                Entry::Occupied(mut entry) => match entry.get() {
1979                    // Replace a hash node with a revealed leaf node and store leaf node value.
1980                    SparseNode::Hash(hash) => {
1981                        let mut full = *entry.key();
1982                        full.extend(&leaf.key);
1983                        self.inner.values.insert(full, leaf.value.clone());
1984                        entry.insert(SparseNode::Leaf {
1985                            key: leaf.key,
1986                            // Memoize the hash of a previously blinded node in a new leaf
1987                            // node.
1988                            hash: Some(*hash),
1989                        });
1990                    }
1991                    // Leaf node already exists.
1992                    SparseNode::Leaf { .. } => {}
1993                    // All other node types can't be handled.
1994                    node @ (SparseNode::Empty |
1995                    SparseNode::Extension { .. } |
1996                    SparseNode::Branch { .. }) => {
1997                        return Err(SparseTrieErrorKind::Reveal {
1998                            path: *entry.key(),
1999                            node: Box::new(node.clone()),
2000                        }
2001                        .into())
2002                    }
2003                },
2004                Entry::Vacant(entry) => {
2005                    let mut full = *entry.key();
2006                    full.extend(&leaf.key);
2007                    entry.insert(SparseNode::new_leaf(leaf.key));
2008                    self.inner.values.insert(full, leaf.value.clone());
2009                }
2010            },
2011        }
2012
2013        Ok(())
2014    }
2015
2016    /// Reveals either a node or its hash placeholder based on the provided child data.
2017    ///
2018    /// When traversing the trie, we often encounter references to child nodes that
2019    /// are either directly embedded or represented by their hash. This method
2020    /// handles both cases:
2021    ///
2022    /// 1. If the child data represents a hash (32+1=33 bytes), store it as a hash node
2023    /// 2. Otherwise, decode the data as a [`TrieNode`] and recursively reveal it using
2024    ///    `reveal_node`
2025    ///
2026    /// # Returns
2027    ///
2028    /// Returns `Ok(())` if successful, or an error if the node cannot be revealed.
2029    ///
2030    /// # Error Handling
2031    ///
2032    /// Will error if there's a conflict between a new hash node and an existing one
2033    /// at the same path
2034    fn reveal_node_or_hash(&mut self, path: Nibbles, child: &[u8]) -> SparseTrieResult<()> {
2035        if child.len() == B256::len_bytes() + 1 {
2036            let hash = B256::from_slice(&child[1..]);
2037            match self.nodes.entry(path) {
2038                Entry::Occupied(entry) => match entry.get() {
2039                    // Hash node with a different hash can't be handled.
2040                    SparseNode::Hash(previous_hash) if previous_hash != &hash => {
2041                        return Err(SparseTrieErrorKind::Reveal {
2042                            path: *entry.key(),
2043                            node: Box::new(SparseNode::Hash(hash)),
2044                        }
2045                        .into())
2046                    }
2047                    _ => {}
2048                },
2049                Entry::Vacant(entry) => {
2050                    entry.insert(SparseNode::Hash(hash));
2051                }
2052            }
2053            return Ok(())
2054        }
2055
2056        self.reveal_node(path, &TrieNode::decode(&mut &child[..])?, TrieMasks::none())
2057    }
2058
2059    /// Recalculates and updates the RLP hashes for the changed nodes in this subtrie.
2060    ///
2061    /// The function starts from the subtrie root, traverses down to leaves, and then calculates
2062    /// the hashes from leaves back up to the root. It uses a stack from [`SparseSubtrieBuffers`] to
2063    /// track the traversal and accumulate RLP encodings.
2064    ///
2065    /// # Parameters
2066    ///
2067    /// - `prefix_set`: The set of trie paths whose nodes have changed.
2068    /// - `update_actions`: A buffer which `SparseTrieUpdatesAction`s will be written to in the
2069    ///   event that any changes to the top-level updates are required. If None then update
2070    ///   retention is disabled.
2071    /// - `branch_node_tree_masks`: The tree masks for branch nodes
2072    /// - `branch_node_hash_masks`: The hash masks for branch nodes
2073    ///
2074    /// # Returns
2075    ///
2076    /// A tuple containing the root node of the updated subtrie.
2077    ///
2078    /// # Panics
2079    ///
2080    /// If the node at the root path does not exist.
2081    #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(root = ?self.path), ret)]
2082    fn update_hashes(
2083        &mut self,
2084        prefix_set: &mut PrefixSet,
2085        update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
2086        branch_node_tree_masks: &HashMap<Nibbles, TrieMask>,
2087        branch_node_hash_masks: &HashMap<Nibbles, TrieMask>,
2088    ) -> RlpNode {
2089        trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
2090
2091        debug_assert!(prefix_set.iter().all(|path| path.starts_with(&self.path)));
2092
2093        debug_assert!(self.inner.buffers.path_stack.is_empty());
2094        self.inner
2095            .buffers
2096            .path_stack
2097            .push(RlpNodePathStackItem { path: self.path, is_in_prefix_set: None });
2098
2099        while let Some(stack_item) = self.inner.buffers.path_stack.pop() {
2100            let path = stack_item.path;
2101            let node = self
2102                .nodes
2103                .get_mut(&path)
2104                .unwrap_or_else(|| panic!("node at path {path:?} does not exist"));
2105
2106            self.inner.rlp_node(
2107                prefix_set,
2108                update_actions,
2109                stack_item,
2110                node,
2111                branch_node_tree_masks,
2112                branch_node_hash_masks,
2113            );
2114        }
2115
2116        debug_assert_eq!(self.inner.buffers.rlp_node_stack.len(), 1);
2117        self.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
2118    }
2119
2120    /// Removes all nodes and values from the subtrie, resetting it to a blank state
2121    /// with only an empty root node. This is used when a storage root is deleted.
2122    fn wipe(&mut self) {
2123        self.nodes = HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]);
2124        self.inner.clear();
2125    }
2126
2127    /// Clears the subtrie, keeping the data structures allocated.
2128    pub(crate) fn clear(&mut self) {
2129        self.nodes.clear();
2130        self.inner.clear();
2131    }
2132
2133    /// Shrinks the capacity of the subtrie's node storage.
2134    pub(crate) fn shrink_nodes_to(&mut self, size: usize) {
2135        self.nodes.shrink_to(size);
2136    }
2137
2138    /// Shrinks the capacity of the subtrie's value storage.
2139    pub(crate) fn shrink_values_to(&mut self, size: usize) {
2140        self.inner.values.shrink_to(size);
2141    }
2142}
2143
2144/// Helper type for [`SparseSubtrie`] to mutably access only a subset of fields from the original
2145/// struct.
2146#[derive(Clone, PartialEq, Eq, Debug, Default)]
2147struct SparseSubtrieInner {
2148    /// Map from leaf key paths to their values.
2149    /// All values are stored here instead of directly in leaf nodes.
2150    values: HashMap<Nibbles, Vec<u8>>,
2151    /// Reusable buffers for [`SparseSubtrie::update_hashes`].
2152    buffers: SparseSubtrieBuffers,
2153}
2154
2155impl SparseSubtrieInner {
2156    /// Computes the RLP encoding and its hash for a single (trie node)[`SparseNode`].
2157    ///
2158    /// # Deferred Processing
2159    ///
2160    /// When an extension or a branch node depends on child nodes that haven't been computed yet,
2161    /// the function pushes the current node back onto the path stack along with its children,
2162    /// then returns early. This allows the iterative algorithm to process children first before
2163    /// retrying the parent.
2164    ///
2165    /// # Parameters
2166    ///
2167    /// - `prefix_set`: Set of prefixes (key paths) that have been marked as updated
2168    /// - `update_actions`: A buffer which `SparseTrieUpdatesAction`s will be written to in the
2169    ///   event that any changes to the top-level updates are required. If None then update
2170    ///   retention is disabled.
2171    /// - `stack_item`: The stack item to process
2172    /// - `node`: The sparse node to process (will be mutated to update hash)
2173    /// - `branch_node_tree_masks`: The tree masks for branch nodes
2174    /// - `branch_node_hash_masks`: The hash masks for branch nodes
2175    ///
2176    /// # Side Effects
2177    ///
2178    /// - Updates the node's hash field after computing RLP
2179    /// - Pushes nodes to [`SparseSubtrieBuffers::path_stack`] to manage traversal
2180    /// - May push items onto the path stack for deferred processing
2181    ///
2182    /// # Exit condition
2183    ///
2184    /// Once all nodes have been processed and all RLPs and hashes calculated, pushes the root node
2185    /// onto the [`SparseSubtrieBuffers::rlp_node_stack`] and exits.
2186    fn rlp_node(
2187        &mut self,
2188        prefix_set: &mut PrefixSet,
2189        update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
2190        mut stack_item: RlpNodePathStackItem,
2191        node: &mut SparseNode,
2192        branch_node_tree_masks: &HashMap<Nibbles, TrieMask>,
2193        branch_node_hash_masks: &HashMap<Nibbles, TrieMask>,
2194    ) {
2195        let path = stack_item.path;
2196        trace!(
2197            target: "trie::parallel_sparse",
2198            ?path,
2199            ?node,
2200            "Calculating node RLP"
2201        );
2202
2203        // Check if the path is in the prefix set.
2204        // First, check the cached value. If it's `None`, then check the prefix set, and update
2205        // the cached value.
2206        let mut prefix_set_contains = |path: &Nibbles| {
2207            *stack_item.is_in_prefix_set.get_or_insert_with(|| prefix_set.contains(path))
2208        };
2209
2210        let (rlp_node, node_type) = match node {
2211            SparseNode::Empty => (RlpNode::word_rlp(&EMPTY_ROOT_HASH), SparseNodeType::Empty),
2212            SparseNode::Hash(hash) => {
2213                // Return pre-computed hash of a blinded node immediately
2214                (RlpNode::word_rlp(hash), SparseNodeType::Hash)
2215            }
2216            SparseNode::Leaf { key, hash } => {
2217                let mut path = path;
2218                path.extend(key);
2219                let value = self.values.get(&path);
2220                if let Some(hash) = hash.filter(|_| !prefix_set_contains(&path) || value.is_none())
2221                {
2222                    // If the node hash is already computed, and either the node path is not in
2223                    // the prefix set or the leaf doesn't belong to the current trie (its value is
2224                    // absent), return the pre-computed hash
2225                    (RlpNode::word_rlp(&hash), SparseNodeType::Leaf)
2226                } else {
2227                    // Encode the leaf node and update its hash
2228                    let value = self.values.get(&path).unwrap();
2229                    self.buffers.rlp_buf.clear();
2230                    let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.buffers.rlp_buf);
2231                    *hash = rlp_node.as_hash();
2232                    (rlp_node, SparseNodeType::Leaf)
2233                }
2234            }
2235            SparseNode::Extension { key, hash, store_in_db_trie } => {
2236                let mut child_path = path;
2237                child_path.extend(key);
2238                if let Some((hash, store_in_db_trie)) =
2239                    hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
2240                {
2241                    // If the node hash is already computed, and the node path is not in
2242                    // the prefix set, return the pre-computed hash
2243                    (
2244                        RlpNode::word_rlp(&hash),
2245                        SparseNodeType::Extension { store_in_db_trie: Some(store_in_db_trie) },
2246                    )
2247                } else if self.buffers.rlp_node_stack.last().is_some_and(|e| e.path == child_path) {
2248                    // Top of the stack has the child node, we can encode the extension node and
2249                    // update its hash
2250                    let RlpNodeStackItem { path: _, rlp_node: child, node_type: child_node_type } =
2251                        self.buffers.rlp_node_stack.pop().unwrap();
2252                    self.buffers.rlp_buf.clear();
2253                    let rlp_node =
2254                        ExtensionNodeRef::new(key, &child).rlp(&mut self.buffers.rlp_buf);
2255                    *hash = rlp_node.as_hash();
2256
2257                    let store_in_db_trie_value = child_node_type.store_in_db_trie();
2258
2259                    trace!(
2260                        target: "trie::parallel_sparse",
2261                        ?path,
2262                        ?child_path,
2263                        ?child_node_type,
2264                        "Extension node"
2265                    );
2266
2267                    *store_in_db_trie = store_in_db_trie_value;
2268
2269                    (
2270                        rlp_node,
2271                        SparseNodeType::Extension {
2272                            // Inherit the `store_in_db_trie` flag from the child node, which is
2273                            // always the branch node
2274                            store_in_db_trie: store_in_db_trie_value,
2275                        },
2276                    )
2277                } else {
2278                    // Need to defer processing until child is computed, on the next
2279                    // invocation update the node's hash.
2280                    self.buffers.path_stack.extend([
2281                        RlpNodePathStackItem {
2282                            path,
2283                            is_in_prefix_set: Some(prefix_set_contains(&path)),
2284                        },
2285                        RlpNodePathStackItem { path: child_path, is_in_prefix_set: None },
2286                    ]);
2287                    return
2288                }
2289            }
2290            SparseNode::Branch { state_mask, hash, store_in_db_trie } => {
2291                if let Some((hash, store_in_db_trie)) =
2292                    hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
2293                {
2294                    // If the node hash is already computed, and the node path is not in
2295                    // the prefix set, return the pre-computed hash
2296                    self.buffers.rlp_node_stack.push(RlpNodeStackItem {
2297                        path,
2298                        rlp_node: RlpNode::word_rlp(&hash),
2299                        node_type: SparseNodeType::Branch {
2300                            store_in_db_trie: Some(store_in_db_trie),
2301                        },
2302                    });
2303                    return
2304                }
2305
2306                let retain_updates = update_actions.is_some() && prefix_set_contains(&path);
2307
2308                self.buffers.branch_child_buf.clear();
2309                // Walk children in a reverse order from `f` to `0`, so we pop the `0` first
2310                // from the stack and keep walking in the sorted order.
2311                for bit in CHILD_INDEX_RANGE.rev() {
2312                    if state_mask.is_bit_set(bit) {
2313                        let mut child = path;
2314                        child.push_unchecked(bit);
2315                        self.buffers.branch_child_buf.push(child);
2316                    }
2317                }
2318
2319                self.buffers
2320                    .branch_value_stack_buf
2321                    .resize(self.buffers.branch_child_buf.len(), Default::default());
2322                let mut added_children = false;
2323
2324                let mut tree_mask = TrieMask::default();
2325                let mut hash_mask = TrieMask::default();
2326                let mut hashes = Vec::new();
2327                for (i, child_path) in self.buffers.branch_child_buf.iter().enumerate() {
2328                    if self.buffers.rlp_node_stack.last().is_some_and(|e| &e.path == child_path) {
2329                        let RlpNodeStackItem {
2330                            path: _,
2331                            rlp_node: child,
2332                            node_type: child_node_type,
2333                        } = self.buffers.rlp_node_stack.pop().unwrap();
2334
2335                        // Update the masks only if we need to retain trie updates
2336                        if retain_updates {
2337                            // SAFETY: it's a child, so it's never empty
2338                            let last_child_nibble = child_path.last().unwrap();
2339
2340                            // Determine whether we need to set trie mask bit.
2341                            let should_set_tree_mask_bit = if let Some(store_in_db_trie) =
2342                                child_node_type.store_in_db_trie()
2343                            {
2344                                // A branch or an extension node explicitly set the
2345                                // `store_in_db_trie` flag
2346                                store_in_db_trie
2347                            } else {
2348                                // A blinded node has the tree mask bit set
2349                                child_node_type.is_hash() &&
2350                                    branch_node_tree_masks
2351                                        .get(&path)
2352                                        .is_some_and(|mask| mask.is_bit_set(last_child_nibble))
2353                            };
2354                            if should_set_tree_mask_bit {
2355                                tree_mask.set_bit(last_child_nibble);
2356                            }
2357
2358                            // Set the hash mask. If a child node is a revealed branch node OR
2359                            // is a blinded node that has its hash mask bit set according to the
2360                            // database, set the hash mask bit and save the hash.
2361                            let hash = child.as_hash().filter(|_| {
2362                                child_node_type.is_branch() ||
2363                                    (child_node_type.is_hash() &&
2364                                        branch_node_hash_masks.get(&path).is_some_and(
2365                                            |mask| mask.is_bit_set(last_child_nibble),
2366                                        ))
2367                            });
2368                            if let Some(hash) = hash {
2369                                hash_mask.set_bit(last_child_nibble);
2370                                hashes.push(hash);
2371                            }
2372                        }
2373
2374                        // Insert children in the resulting buffer in a normal order,
2375                        // because initially we iterated in reverse.
2376                        // SAFETY: i < len and len is never 0
2377                        let original_idx = self.buffers.branch_child_buf.len() - i - 1;
2378                        self.buffers.branch_value_stack_buf[original_idx] = child;
2379                        added_children = true;
2380                    } else {
2381                        // Need to defer processing until children are computed, on the next
2382                        // invocation update the node's hash.
2383                        debug_assert!(!added_children);
2384                        self.buffers.path_stack.push(RlpNodePathStackItem {
2385                            path,
2386                            is_in_prefix_set: Some(prefix_set_contains(&path)),
2387                        });
2388                        self.buffers.path_stack.extend(
2389                            self.buffers
2390                                .branch_child_buf
2391                                .drain(..)
2392                                .map(|path| RlpNodePathStackItem { path, is_in_prefix_set: None }),
2393                        );
2394                        return
2395                    }
2396                }
2397
2398                trace!(
2399                    target: "trie::parallel_sparse",
2400                    ?path,
2401                    ?tree_mask,
2402                    ?hash_mask,
2403                    "Branch node masks"
2404                );
2405
2406                // Top of the stack has all children node, we can encode the branch node and
2407                // update its hash
2408                self.buffers.rlp_buf.clear();
2409                let branch_node_ref =
2410                    BranchNodeRef::new(&self.buffers.branch_value_stack_buf, *state_mask);
2411                let rlp_node = branch_node_ref.rlp(&mut self.buffers.rlp_buf);
2412                *hash = rlp_node.as_hash();
2413
2414                // Save a branch node update only if it's not a root node, and we need to
2415                // persist updates.
2416                let store_in_db_trie_value = if let Some(update_actions) =
2417                    update_actions.as_mut().filter(|_| retain_updates && !path.is_empty())
2418                {
2419                    let store_in_db_trie = !tree_mask.is_empty() || !hash_mask.is_empty();
2420                    if store_in_db_trie {
2421                        // Store in DB trie if there are either any children that are stored in
2422                        // the DB trie, or any children represent hashed values
2423                        hashes.reverse();
2424                        let branch_node = BranchNodeCompact::new(
2425                            *state_mask,
2426                            tree_mask,
2427                            hash_mask,
2428                            hashes,
2429                            hash.filter(|_| path.is_empty()),
2430                        );
2431                        update_actions
2432                            .push(SparseTrieUpdatesAction::InsertUpdated(path, branch_node));
2433                    } else if branch_node_tree_masks.get(&path).is_some_and(|mask| !mask.is_empty()) ||
2434                        branch_node_hash_masks.get(&path).is_some_and(|mask| !mask.is_empty())
2435                    {
2436                        // If new tree and hash masks are empty, but previously they weren't, we
2437                        // need to remove the node update and add the node itself to the list of
2438                        // removed nodes.
2439                        update_actions.push(SparseTrieUpdatesAction::InsertRemoved(path));
2440                    } else if branch_node_tree_masks.get(&path).is_none_or(|mask| mask.is_empty()) &&
2441                        branch_node_hash_masks.get(&path).is_none_or(|mask| mask.is_empty())
2442                    {
2443                        // If new tree and hash masks are empty, and they were previously empty
2444                        // as well, we need to remove the node update.
2445                        update_actions.push(SparseTrieUpdatesAction::RemoveUpdated(path));
2446                    }
2447
2448                    store_in_db_trie
2449                } else {
2450                    false
2451                };
2452                *store_in_db_trie = Some(store_in_db_trie_value);
2453
2454                (
2455                    rlp_node,
2456                    SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie_value) },
2457                )
2458            }
2459        };
2460
2461        self.buffers.rlp_node_stack.push(RlpNodeStackItem { path, rlp_node, node_type });
2462        trace!(
2463            target: "trie::parallel_sparse",
2464            ?path,
2465            ?node_type,
2466            "Added node to RLP node stack"
2467        );
2468    }
2469
2470    /// Clears the subtrie, keeping the data structures allocated.
2471    fn clear(&mut self) {
2472        self.values.clear();
2473        self.buffers.clear();
2474    }
2475}
2476
2477/// Represents the outcome of processing a node during leaf insertion
2478#[derive(Clone, Debug, PartialEq, Eq, Default)]
2479pub enum LeafUpdateStep {
2480    /// Continue traversing to the next node
2481    Continue {
2482        /// The next node path to process
2483        next_node: Nibbles,
2484    },
2485    /// Update is complete with nodes inserted
2486    Complete {
2487        /// The node paths that were inserted during this step
2488        inserted_nodes: Vec<Nibbles>,
2489        /// Path to a node which may need to be revealed
2490        reveal_path: Option<Nibbles>,
2491    },
2492    /// The node was not found
2493    #[default]
2494    NodeNotFound,
2495}
2496
2497impl LeafUpdateStep {
2498    /// Creates a step to continue with the next node
2499    pub const fn continue_with(next_node: Nibbles) -> Self {
2500        Self::Continue { next_node }
2501    }
2502
2503    /// Creates a step indicating completion with inserted nodes
2504    pub const fn complete_with_insertions(
2505        inserted_nodes: Vec<Nibbles>,
2506        reveal_path: Option<Nibbles>,
2507    ) -> Self {
2508        Self::Complete { inserted_nodes, reveal_path }
2509    }
2510}
2511
2512/// Sparse Subtrie Type.
2513///
2514/// Used to determine the type of subtrie a certain path belongs to:
2515/// - Paths in the range `0x..=0xf` belong to the upper subtrie.
2516/// - Paths in the range `0x00..` belong to one of the lower subtries. The index of the lower
2517///   subtrie is determined by the first [`UPPER_TRIE_MAX_DEPTH`] nibbles of the path.
2518///
2519/// There can be at most [`NUM_LOWER_SUBTRIES`] lower subtries.
2520#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2521pub enum SparseSubtrieType {
2522    /// Upper subtrie with paths in the range `0x..=0xf`
2523    Upper,
2524    /// Lower subtrie with paths in the range `0x00..`. Includes the index of the subtrie,
2525    /// according to the path prefix.
2526    Lower(usize),
2527}
2528
2529impl SparseSubtrieType {
2530    /// Returns true if a node at a path of the given length would be placed in the upper subtrie.
2531    ///
2532    /// Nodes with paths shorter than [`UPPER_TRIE_MAX_DEPTH`] nibbles belong to the upper subtrie,
2533    /// while longer paths belong to the lower subtries.
2534    pub const fn path_len_is_upper(len: usize) -> bool {
2535        len < UPPER_TRIE_MAX_DEPTH
2536    }
2537
2538    /// Returns the type of subtrie based on the given path.
2539    pub fn from_path(path: &Nibbles) -> Self {
2540        if Self::path_len_is_upper(path.len()) {
2541            Self::Upper
2542        } else {
2543            Self::Lower(path_subtrie_index_unchecked(path))
2544        }
2545    }
2546
2547    /// Returns the index of the lower subtrie, if it exists.
2548    pub const fn lower_index(&self) -> Option<usize> {
2549        match self {
2550            Self::Upper => None,
2551            Self::Lower(index) => Some(*index),
2552        }
2553    }
2554}
2555
2556impl Ord for SparseSubtrieType {
2557    /// Orders two [`SparseSubtrieType`]s such that `Upper` is less than `Lower(_)`, and `Lower`s
2558    /// are ordered by their index.
2559    fn cmp(&self, other: &Self) -> Ordering {
2560        match (self, other) {
2561            (Self::Upper, Self::Upper) => Ordering::Equal,
2562            (Self::Upper, Self::Lower(_)) => Ordering::Less,
2563            (Self::Lower(_), Self::Upper) => Ordering::Greater,
2564            (Self::Lower(idx_a), Self::Lower(idx_b)) if idx_a == idx_b => Ordering::Equal,
2565            (Self::Lower(idx_a), Self::Lower(idx_b)) => idx_a.cmp(idx_b),
2566        }
2567    }
2568}
2569
2570impl PartialOrd for SparseSubtrieType {
2571    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2572        Some(self.cmp(other))
2573    }
2574}
2575
2576/// Collection of reusable buffers for calculating subtrie hashes.
2577///
2578/// These buffers reduce allocations when computing RLP representations during trie updates.
2579#[derive(Clone, PartialEq, Eq, Debug, Default)]
2580pub struct SparseSubtrieBuffers {
2581    /// Stack of RLP node paths
2582    path_stack: Vec<RlpNodePathStackItem>,
2583    /// Stack of RLP nodes
2584    rlp_node_stack: Vec<RlpNodeStackItem>,
2585    /// Reusable branch child path
2586    branch_child_buf: SmallVec<[Nibbles; 16]>,
2587    /// Reusable branch value stack
2588    branch_value_stack_buf: SmallVec<[RlpNode; 16]>,
2589    /// Reusable RLP buffer
2590    rlp_buf: Vec<u8>,
2591}
2592
2593impl SparseSubtrieBuffers {
2594    /// Clears all buffers.
2595    fn clear(&mut self) {
2596        self.path_stack.clear();
2597        self.path_stack.shrink_to_fit();
2598
2599        self.rlp_node_stack.clear();
2600        self.rlp_node_stack.shrink_to_fit();
2601
2602        self.branch_child_buf.clear();
2603        self.branch_child_buf.shrink_to_fit();
2604
2605        self.branch_value_stack_buf.clear();
2606        self.branch_value_stack_buf.shrink_to_fit();
2607
2608        self.rlp_buf.clear();
2609        self.rlp_buf.shrink_to_fit();
2610    }
2611}
2612
2613/// RLP node path stack item.
2614#[derive(Clone, PartialEq, Eq, Debug)]
2615pub struct RlpNodePathStackItem {
2616    /// Path to the node.
2617    pub path: Nibbles,
2618    /// Whether the path is in the prefix set. If [`None`], then unknown yet.
2619    pub is_in_prefix_set: Option<bool>,
2620}
2621
2622/// Changed subtrie.
2623#[derive(Debug)]
2624struct ChangedSubtrie {
2625    /// Lower subtrie index in the range [0, [`NUM_LOWER_SUBTRIES`]).
2626    index: usize,
2627    /// Changed subtrie
2628    subtrie: Box<SparseSubtrie>,
2629    /// Prefix set of keys that belong to the subtrie.
2630    prefix_set: PrefixSet,
2631    /// Reusable buffer for collecting [`SparseTrieUpdatesAction`]s during computations. Will be
2632    /// None if update retention is disabled.
2633    update_actions_buf: Option<Vec<SparseTrieUpdatesAction>>,
2634}
2635
2636/// Convert first [`UPPER_TRIE_MAX_DEPTH`] nibbles of the path into a lower subtrie index in the
2637/// range [0, [`NUM_LOWER_SUBTRIES`]).
2638///
2639/// # Panics
2640///
2641/// If the path is shorter than [`UPPER_TRIE_MAX_DEPTH`] nibbles.
2642fn path_subtrie_index_unchecked(path: &Nibbles) -> usize {
2643    debug_assert_eq!(UPPER_TRIE_MAX_DEPTH, 2);
2644    path.get_byte_unchecked(0) as usize
2645}
2646
2647/// Used by lower subtries to communicate updates to the top-level [`SparseTrieUpdates`] set.
2648#[derive(Clone, Debug, Eq, PartialEq)]
2649enum SparseTrieUpdatesAction {
2650    /// Remove the path from the `updated_nodes`, if it was present, and add it to `removed_nodes`.
2651    InsertRemoved(Nibbles),
2652    /// Remove the path from the `updated_nodes`, if it was present, leaving `removed_nodes`
2653    /// unaffected.
2654    RemoveUpdated(Nibbles),
2655    /// Insert the branch node into `updated_nodes`.
2656    InsertUpdated(Nibbles, BranchNodeCompact),
2657}
2658
2659#[cfg(test)]
2660mod tests {
2661    use super::{
2662        path_subtrie_index_unchecked, LowerSparseSubtrie, ParallelSparseTrie, SparseSubtrie,
2663        SparseSubtrieType,
2664    };
2665    use crate::trie::ChangedSubtrie;
2666    use alloy_primitives::{
2667        b256, hex,
2668        map::{B256Set, DefaultHashBuilder, HashMap},
2669        B256, U256,
2670    };
2671    use alloy_rlp::{Decodable, Encodable};
2672    use alloy_trie::{BranchNodeCompact, Nibbles};
2673    use assert_matches::assert_matches;
2674    use itertools::Itertools;
2675    use proptest::{prelude::*, sample::SizeRange};
2676    use proptest_arbitrary_interop::arb;
2677    use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind};
2678    use reth_primitives_traits::Account;
2679    use reth_provider::{test_utils::create_test_provider_factory, TrieWriter};
2680    use reth_trie::{
2681        hashed_cursor::{noop::NoopHashedAccountCursor, HashedPostStateAccountCursor},
2682        node_iter::{TrieElement, TrieNodeIter},
2683        trie_cursor::{noop::NoopAccountTrieCursor, TrieCursor, TrieCursorFactory},
2684        walker::TrieWalker,
2685        HashedPostState,
2686    };
2687    use reth_trie_common::{
2688        prefix_set::PrefixSetMut,
2689        proof::{ProofNodes, ProofRetainer},
2690        updates::TrieUpdates,
2691        BranchNode, ExtensionNode, HashBuilder, LeafNode, RlpNode, TrieMask, TrieNode,
2692        EMPTY_ROOT_HASH,
2693    };
2694    use reth_trie_db::DatabaseTrieCursorFactory;
2695    use reth_trie_sparse::{
2696        provider::{DefaultTrieNodeProvider, RevealedNode, TrieNodeProvider},
2697        LeafLookup, LeafLookupError, RevealedSparseNode, SerialSparseTrie, SparseNode,
2698        SparseTrieInterface, SparseTrieUpdates, TrieMasks,
2699    };
2700    use std::collections::{BTreeMap, BTreeSet};
2701
2702    /// Pad nibbles to the length of a B256 hash with zeros on the right.
2703    fn pad_nibbles_right(mut nibbles: Nibbles) -> Nibbles {
2704        nibbles.extend(&Nibbles::from_nibbles_unchecked(vec![
2705            0;
2706            B256::len_bytes() * 2 - nibbles.len()
2707        ]));
2708        nibbles
2709    }
2710
2711    /// Mock trie node provider for testing that allows pre-setting nodes at specific paths.
2712    ///
2713    /// This provider can be used in tests to simulate trie nodes that need to be revealed
2714    /// during trie operations, particularly when collapsing branch nodes during leaf removal.
2715    #[derive(Debug, Clone)]
2716    struct MockTrieNodeProvider {
2717        /// Mapping from path to revealed node data
2718        nodes: HashMap<Nibbles, RevealedNode, DefaultHashBuilder>,
2719    }
2720
2721    impl MockTrieNodeProvider {
2722        /// Creates a new empty mock provider
2723        fn new() -> Self {
2724            Self { nodes: HashMap::default() }
2725        }
2726
2727        /// Adds a revealed node at the specified path
2728        fn add_revealed_node(&mut self, path: Nibbles, node: RevealedNode) {
2729            self.nodes.insert(path, node);
2730        }
2731    }
2732
2733    impl TrieNodeProvider for MockTrieNodeProvider {
2734        fn trie_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
2735            Ok(self.nodes.get(path).cloned())
2736        }
2737    }
2738
2739    fn create_account(nonce: u64) -> Account {
2740        Account { nonce, ..Default::default() }
2741    }
2742
2743    fn encode_account_value(nonce: u64) -> Vec<u8> {
2744        let account = Account { nonce, ..Default::default() };
2745        let trie_account = account.into_trie_account(EMPTY_ROOT_HASH);
2746        let mut buf = Vec::new();
2747        trie_account.encode(&mut buf);
2748        buf
2749    }
2750
2751    /// Test context that provides helper methods for trie testing
2752    #[derive(Default)]
2753    struct ParallelSparseTrieTestContext;
2754
2755    impl ParallelSparseTrieTestContext {
2756        /// Assert that a lower subtrie exists at the given path
2757        fn assert_subtrie_exists(&self, trie: &ParallelSparseTrie, path: &Nibbles) {
2758            let idx = path_subtrie_index_unchecked(path);
2759            assert!(
2760                trie.lower_subtries[idx].as_revealed_ref().is_some(),
2761                "Expected lower subtrie at path {path:?} to exist",
2762            );
2763        }
2764
2765        /// Get a lower subtrie, panicking if it doesn't exist
2766        fn get_subtrie<'a>(
2767            &self,
2768            trie: &'a ParallelSparseTrie,
2769            path: &Nibbles,
2770        ) -> &'a SparseSubtrie {
2771            let idx = path_subtrie_index_unchecked(path);
2772            trie.lower_subtries[idx]
2773                .as_revealed_ref()
2774                .unwrap_or_else(|| panic!("Lower subtrie at path {path:?} should exist"))
2775        }
2776
2777        /// Assert that a lower subtrie has a specific path field value
2778        fn assert_subtrie_path(
2779            &self,
2780            trie: &ParallelSparseTrie,
2781            subtrie_prefix: impl AsRef<[u8]>,
2782            expected_path: impl AsRef<[u8]>,
2783        ) {
2784            let subtrie_prefix = Nibbles::from_nibbles(subtrie_prefix);
2785            let expected_path = Nibbles::from_nibbles(expected_path);
2786            let idx = path_subtrie_index_unchecked(&subtrie_prefix);
2787
2788            let subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap_or_else(|| {
2789                panic!("Lower subtrie at prefix {subtrie_prefix:?} should exist")
2790            });
2791
2792            assert_eq!(
2793                subtrie.path, expected_path,
2794                "Subtrie at prefix {subtrie_prefix:?} should have path {expected_path:?}, but has {:?}",
2795                subtrie.path
2796            );
2797        }
2798
2799        /// Create test leaves with consecutive account values
2800        fn create_test_leaves(&self, paths: &[&[u8]]) -> Vec<(Nibbles, Vec<u8>)> {
2801            paths
2802                .iter()
2803                .enumerate()
2804                .map(|(i, path)| (Nibbles::from_nibbles(path), encode_account_value(i as u64 + 1)))
2805                .collect()
2806        }
2807
2808        /// Create a single test leaf with the given path and value nonce
2809        fn create_test_leaf(&self, path: impl AsRef<[u8]>, value_nonce: u64) -> (Nibbles, Vec<u8>) {
2810            (Nibbles::from_nibbles(path), encode_account_value(value_nonce))
2811        }
2812
2813        /// Update multiple leaves in the trie
2814        fn update_leaves(
2815            &self,
2816            trie: &mut ParallelSparseTrie,
2817            leaves: impl IntoIterator<Item = (Nibbles, Vec<u8>)>,
2818        ) {
2819            for (path, value) in leaves {
2820                trie.update_leaf(path, value, DefaultTrieNodeProvider).unwrap();
2821            }
2822        }
2823
2824        /// Create an assertion builder for a subtrie
2825        fn assert_subtrie<'a>(
2826            &self,
2827            trie: &'a ParallelSparseTrie,
2828            path: Nibbles,
2829        ) -> SubtrieAssertion<'a> {
2830            self.assert_subtrie_exists(trie, &path);
2831            let subtrie = self.get_subtrie(trie, &path);
2832            SubtrieAssertion::new(subtrie)
2833        }
2834
2835        /// Create an assertion builder for the upper subtrie
2836        fn assert_upper_subtrie<'a>(&self, trie: &'a ParallelSparseTrie) -> SubtrieAssertion<'a> {
2837            SubtrieAssertion::new(&trie.upper_subtrie)
2838        }
2839
2840        /// Assert the root, trie updates, and nodes against the hash builder output.
2841        fn assert_with_hash_builder(
2842            &self,
2843            trie: &mut ParallelSparseTrie,
2844            hash_builder_root: B256,
2845            hash_builder_updates: TrieUpdates,
2846            hash_builder_proof_nodes: ProofNodes,
2847        ) {
2848            assert_eq!(trie.root(), hash_builder_root);
2849            pretty_assertions::assert_eq!(
2850                BTreeMap::from_iter(trie.updates_ref().updated_nodes.clone()),
2851                BTreeMap::from_iter(hash_builder_updates.account_nodes)
2852            );
2853            assert_eq_parallel_sparse_trie_proof_nodes(trie, hash_builder_proof_nodes);
2854        }
2855    }
2856
2857    /// Assertion builder for subtrie structure
2858    struct SubtrieAssertion<'a> {
2859        subtrie: &'a SparseSubtrie,
2860    }
2861
2862    impl<'a> SubtrieAssertion<'a> {
2863        fn new(subtrie: &'a SparseSubtrie) -> Self {
2864            Self { subtrie }
2865        }
2866
2867        fn has_branch(self, path: &Nibbles, expected_mask_bits: &[u8]) -> Self {
2868            match self.subtrie.nodes.get(path) {
2869                Some(SparseNode::Branch { state_mask, .. }) => {
2870                    for bit in expected_mask_bits {
2871                        assert!(
2872                            state_mask.is_bit_set(*bit),
2873                            "Expected branch at {path:?} to have bit {bit} set, instead mask is: {state_mask:?}",
2874                        );
2875                    }
2876                }
2877                node => panic!("Expected branch node at {path:?}, found {node:?}"),
2878            }
2879            self
2880        }
2881
2882        fn has_leaf(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
2883            match self.subtrie.nodes.get(path) {
2884                Some(SparseNode::Leaf { key, .. }) => {
2885                    assert_eq!(
2886                        *key, *expected_key,
2887                        "Expected leaf at {path:?} to have key {expected_key:?}, found {key:?}",
2888                    );
2889                }
2890                node => panic!("Expected leaf node at {path:?}, found {node:?}"),
2891            }
2892            self
2893        }
2894
2895        fn has_extension(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
2896            match self.subtrie.nodes.get(path) {
2897                Some(SparseNode::Extension { key, .. }) => {
2898                    assert_eq!(
2899                        *key, *expected_key,
2900                        "Expected extension at {path:?} to have key {expected_key:?}, found {key:?}",
2901                    );
2902                }
2903                node => panic!("Expected extension node at {path:?}, found {node:?}"),
2904            }
2905            self
2906        }
2907
2908        fn has_hash(self, path: &Nibbles, expected_hash: &B256) -> Self {
2909            match self.subtrie.nodes.get(path) {
2910                Some(SparseNode::Hash(hash)) => {
2911                    assert_eq!(
2912                        *hash, *expected_hash,
2913                        "Expected hash at {path:?} to be {expected_hash:?}, found {hash:?}",
2914                    );
2915                }
2916                node => panic!("Expected hash node at {path:?}, found {node:?}"),
2917            }
2918            self
2919        }
2920
2921        fn has_value(self, path: &Nibbles, expected_value: &[u8]) -> Self {
2922            let actual = self.subtrie.inner.values.get(path);
2923            assert_eq!(
2924                actual.map(|v| v.as_slice()),
2925                Some(expected_value),
2926                "Expected value at {path:?} to be {expected_value:?}, found {actual:?}",
2927            );
2928            self
2929        }
2930
2931        fn has_no_value(self, path: &Nibbles) -> Self {
2932            let actual = self.subtrie.inner.values.get(path);
2933            assert!(actual.is_none(), "Expected no value at {path:?}, but found {actual:?}");
2934            self
2935        }
2936    }
2937
2938    fn create_leaf_node(key: impl AsRef<[u8]>, value_nonce: u64) -> TrieNode {
2939        TrieNode::Leaf(LeafNode::new(Nibbles::from_nibbles(key), encode_account_value(value_nonce)))
2940    }
2941
2942    fn create_extension_node(key: impl AsRef<[u8]>, child_hash: B256) -> TrieNode {
2943        TrieNode::Extension(ExtensionNode::new(
2944            Nibbles::from_nibbles(key),
2945            RlpNode::word_rlp(&child_hash),
2946        ))
2947    }
2948
2949    fn create_branch_node_with_children(
2950        children_indices: &[u8],
2951        child_hashes: impl IntoIterator<Item = RlpNode>,
2952    ) -> TrieNode {
2953        let mut stack = Vec::new();
2954        let mut state_mask = TrieMask::default();
2955
2956        for (&idx, hash) in children_indices.iter().zip(child_hashes.into_iter()) {
2957            state_mask.set_bit(idx);
2958            stack.push(hash);
2959        }
2960
2961        TrieNode::Branch(BranchNode::new(stack, state_mask))
2962    }
2963
2964    /// Calculate the state root by feeding the provided state to the hash builder and retaining the
2965    /// proofs for the provided targets.
2966    ///
2967    /// Returns the state root and the retained proof nodes.
2968    fn run_hash_builder(
2969        state: impl IntoIterator<Item = (Nibbles, Account)> + Clone,
2970        trie_cursor: impl TrieCursor,
2971        destroyed_accounts: B256Set,
2972        proof_targets: impl IntoIterator<Item = Nibbles>,
2973    ) -> (B256, TrieUpdates, ProofNodes, HashMap<Nibbles, TrieMask>, HashMap<Nibbles, TrieMask>)
2974    {
2975        let mut account_rlp = Vec::new();
2976
2977        let mut hash_builder = HashBuilder::default()
2978            .with_updates(true)
2979            .with_proof_retainer(ProofRetainer::from_iter(proof_targets));
2980
2981        let mut prefix_set = PrefixSetMut::default();
2982        prefix_set.extend_keys(state.clone().into_iter().map(|(nibbles, _)| nibbles));
2983        prefix_set.extend_keys(destroyed_accounts.iter().map(Nibbles::unpack));
2984        let walker = TrieWalker::<_>::state_trie(trie_cursor, prefix_set.freeze())
2985            .with_deletions_retained(true);
2986        let hashed_post_state = HashedPostState::default()
2987            .with_accounts(state.into_iter().map(|(nibbles, account)| {
2988                (nibbles.pack().into_inner().unwrap().into(), Some(account))
2989            }))
2990            .into_sorted();
2991        let mut node_iter = TrieNodeIter::state_trie(
2992            walker,
2993            HashedPostStateAccountCursor::new(
2994                NoopHashedAccountCursor::default(),
2995                hashed_post_state.accounts(),
2996            ),
2997        );
2998
2999        while let Some(node) = node_iter.try_next().unwrap() {
3000            match node {
3001                TrieElement::Branch(branch) => {
3002                    hash_builder.add_branch(branch.key, branch.value, branch.children_are_in_trie);
3003                }
3004                TrieElement::Leaf(key, account) => {
3005                    let account = account.into_trie_account(EMPTY_ROOT_HASH);
3006                    account.encode(&mut account_rlp);
3007
3008                    hash_builder.add_leaf(Nibbles::unpack(key), &account_rlp);
3009                    account_rlp.clear();
3010                }
3011            }
3012        }
3013        let root = hash_builder.root();
3014        let proof_nodes = hash_builder.take_proof_nodes();
3015        let branch_node_hash_masks = hash_builder
3016            .updated_branch_nodes
3017            .clone()
3018            .unwrap_or_default()
3019            .iter()
3020            .map(|(path, node)| (*path, node.hash_mask))
3021            .collect();
3022        let branch_node_tree_masks = hash_builder
3023            .updated_branch_nodes
3024            .clone()
3025            .unwrap_or_default()
3026            .iter()
3027            .map(|(path, node)| (*path, node.tree_mask))
3028            .collect();
3029
3030        let mut trie_updates = TrieUpdates::default();
3031        let removed_keys = node_iter.walker.take_removed_keys();
3032        trie_updates.finalize(hash_builder, removed_keys, destroyed_accounts);
3033
3034        (root, trie_updates, proof_nodes, branch_node_hash_masks, branch_node_tree_masks)
3035    }
3036
3037    /// Returns a `ParallelSparseTrie` pre-loaded with the given nodes, as well as leaf values
3038    /// inferred from any provided leaf nodes.
3039    fn new_test_trie<Nodes>(nodes: Nodes) -> ParallelSparseTrie
3040    where
3041        Nodes: Iterator<Item = (Nibbles, SparseNode)>,
3042    {
3043        let mut trie = ParallelSparseTrie::default().with_updates(true);
3044
3045        for (path, node) in nodes {
3046            let subtrie = trie.subtrie_for_path_mut(&path);
3047            if let SparseNode::Leaf { key, .. } = &node {
3048                let mut full_key = path;
3049                full_key.extend(key);
3050                subtrie.inner.values.insert(full_key, "LEAF VALUE".into());
3051            }
3052            subtrie.nodes.insert(path, node);
3053        }
3054        trie
3055    }
3056
3057    fn parallel_sparse_trie_nodes(
3058        sparse_trie: &ParallelSparseTrie,
3059    ) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
3060        let lower_sparse_nodes = sparse_trie
3061            .lower_subtries
3062            .iter()
3063            .filter_map(|subtrie| subtrie.as_revealed_ref())
3064            .flat_map(|subtrie| subtrie.nodes.iter());
3065
3066        let upper_sparse_nodes = sparse_trie.upper_subtrie.nodes.iter();
3067
3068        lower_sparse_nodes.chain(upper_sparse_nodes).sorted_by_key(|(path, _)| *path)
3069    }
3070
3071    /// Assert that the parallel sparse trie nodes and the proof nodes from the hash builder are
3072    /// equal.
3073    fn assert_eq_parallel_sparse_trie_proof_nodes(
3074        sparse_trie: &ParallelSparseTrie,
3075        proof_nodes: ProofNodes,
3076    ) {
3077        let proof_nodes = proof_nodes
3078            .into_nodes_sorted()
3079            .into_iter()
3080            .map(|(path, node)| (path, TrieNode::decode(&mut node.as_ref()).unwrap()));
3081
3082        let all_sparse_nodes = parallel_sparse_trie_nodes(sparse_trie);
3083
3084        for ((proof_node_path, proof_node), (sparse_node_path, sparse_node)) in
3085            proof_nodes.zip(all_sparse_nodes)
3086        {
3087            assert_eq!(&proof_node_path, sparse_node_path);
3088
3089            let equals = match (&proof_node, &sparse_node) {
3090                // Both nodes are empty
3091                (TrieNode::EmptyRoot, SparseNode::Empty) => true,
3092                // Both nodes are branches and have the same state mask
3093                (
3094                    TrieNode::Branch(BranchNode { state_mask: proof_state_mask, .. }),
3095                    SparseNode::Branch { state_mask: sparse_state_mask, .. },
3096                ) => proof_state_mask == sparse_state_mask,
3097                // Both nodes are extensions and have the same key
3098                (
3099                    TrieNode::Extension(ExtensionNode { key: proof_key, .. }),
3100                    SparseNode::Extension { key: sparse_key, .. },
3101                ) |
3102                // Both nodes are leaves and have the same key
3103                (
3104                    TrieNode::Leaf(LeafNode { key: proof_key, .. }),
3105                    SparseNode::Leaf { key: sparse_key, .. },
3106                ) => proof_key == sparse_key,
3107                // Empty and hash nodes are specific to the sparse trie, skip them
3108                (_, SparseNode::Empty | SparseNode::Hash(_)) => continue,
3109                _ => false,
3110            };
3111            assert!(
3112                equals,
3113                "path: {proof_node_path:?}\nproof node: {proof_node:?}\nsparse node: {sparse_node:?}"
3114            );
3115        }
3116    }
3117
3118    #[test]
3119    fn test_get_changed_subtries_empty() {
3120        let mut trie = ParallelSparseTrie::default();
3121        let mut prefix_set = PrefixSetMut::from([Nibbles::default()]).freeze();
3122
3123        let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3124        assert!(subtries.is_empty());
3125        assert_eq!(unchanged_prefix_set, PrefixSetMut::from(prefix_set.iter().copied()));
3126    }
3127
3128    #[test]
3129    fn test_get_changed_subtries() {
3130        // Create a trie with three subtries
3131        let mut trie = ParallelSparseTrie::default();
3132        let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
3133        let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
3134        let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
3135        let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
3136        let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
3137        let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
3138
3139        // Add subtries at specific positions
3140        trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
3141        trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
3142        trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3);
3143
3144        let unchanged_prefix_set = PrefixSetMut::from([
3145            Nibbles::from_nibbles([0x0]),
3146            Nibbles::from_nibbles([0x2, 0x0, 0x0]),
3147        ]);
3148        // Create a prefix set with the keys that match only the second subtrie
3149        let mut prefix_set = PrefixSetMut::from([
3150            // Match second subtrie
3151            Nibbles::from_nibbles([0x1, 0x0, 0x0]),
3152            Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0]),
3153        ]);
3154        prefix_set.extend(unchanged_prefix_set);
3155        let mut prefix_set = prefix_set.freeze();
3156
3157        // Second subtrie should be removed and returned
3158        let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3159        assert_eq!(
3160            subtries
3161                .into_iter()
3162                .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
3163                    (index, subtrie, prefix_set.iter().copied().collect::<Vec<_>>())
3164                })
3165                .collect::<Vec<_>>(),
3166            vec![(
3167                subtrie_2_index,
3168                subtrie_2,
3169                vec![
3170                    Nibbles::from_nibbles([0x1, 0x0, 0x0]),
3171                    Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0])
3172                ]
3173            )]
3174        );
3175        assert_eq!(unchanged_prefix_set, unchanged_prefix_set);
3176        assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_none());
3177
3178        // First subtrie should remain unchanged
3179        assert_eq!(trie.lower_subtries[subtrie_1_index], LowerSparseSubtrie::Revealed(subtrie_1));
3180    }
3181
3182    #[test]
3183    fn test_get_changed_subtries_all() {
3184        // Create a trie with three subtries
3185        let mut trie = ParallelSparseTrie::default();
3186        let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
3187        let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
3188        let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
3189        let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
3190        let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
3191        let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
3192
3193        // Add subtries at specific positions
3194        trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
3195        trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
3196        trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3.clone());
3197
3198        // Create a prefix set that matches any key
3199        let mut prefix_set = PrefixSetMut::all().freeze();
3200
3201        // All subtries should be removed and returned
3202        let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3203        assert_eq!(
3204            subtries
3205                .into_iter()
3206                .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
3207                    (index, subtrie, prefix_set.all())
3208                })
3209                .collect::<Vec<_>>(),
3210            vec![
3211                (subtrie_1_index, subtrie_1, true),
3212                (subtrie_2_index, subtrie_2, true),
3213                (subtrie_3_index, subtrie_3, true)
3214            ]
3215        );
3216        assert_eq!(unchanged_prefix_set, PrefixSetMut::all());
3217
3218        assert!(trie.lower_subtries.iter().all(|subtrie| subtrie.as_revealed_ref().is_none()));
3219    }
3220
3221    #[test]
3222    fn test_sparse_subtrie_type() {
3223        assert_eq!(SparseSubtrieType::from_path(&Nibbles::new()), SparseSubtrieType::Upper);
3224        assert_eq!(
3225            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0])),
3226            SparseSubtrieType::Upper
3227        );
3228        assert_eq!(
3229            SparseSubtrieType::from_path(&Nibbles::from_nibbles([15])),
3230            SparseSubtrieType::Upper
3231        );
3232        assert_eq!(
3233            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0])),
3234            SparseSubtrieType::Lower(0)
3235        );
3236        assert_eq!(
3237            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0, 0])),
3238            SparseSubtrieType::Lower(0)
3239        );
3240        assert_eq!(
3241            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1])),
3242            SparseSubtrieType::Lower(1)
3243        );
3244        assert_eq!(
3245            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1, 0])),
3246            SparseSubtrieType::Lower(1)
3247        );
3248        assert_eq!(
3249            SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 15])),
3250            SparseSubtrieType::Lower(15)
3251        );
3252        assert_eq!(
3253            SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 0])),
3254            SparseSubtrieType::Lower(240)
3255        );
3256        assert_eq!(
3257            SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 1])),
3258            SparseSubtrieType::Lower(241)
3259        );
3260        assert_eq!(
3261            SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15])),
3262            SparseSubtrieType::Lower(255)
3263        );
3264        assert_eq!(
3265            SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15, 15])),
3266            SparseSubtrieType::Lower(255)
3267        );
3268    }
3269
3270    #[test]
3271    fn test_reveal_node_leaves() {
3272        let mut trie = ParallelSparseTrie::default();
3273
3274        // Reveal leaf in the upper trie
3275        {
3276            let path = Nibbles::from_nibbles([0x1]);
3277            let node = create_leaf_node([0x2, 0x3], 42);
3278            let masks = TrieMasks::none();
3279
3280            trie.reveal_nodes(vec![RevealedSparseNode { path, node, masks }]).unwrap();
3281
3282            assert_matches!(
3283                trie.upper_subtrie.nodes.get(&path),
3284                Some(SparseNode::Leaf { key, hash: None })
3285                if key == &Nibbles::from_nibbles([0x2, 0x3])
3286            );
3287
3288            let full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
3289            assert_eq!(
3290                trie.upper_subtrie.inner.values.get(&full_path),
3291                Some(&encode_account_value(42))
3292            );
3293        }
3294
3295        // Reveal leaf in a lower trie
3296        {
3297            let path = Nibbles::from_nibbles([0x1, 0x2]);
3298            let node = create_leaf_node([0x3, 0x4], 42);
3299            let masks = TrieMasks::none();
3300
3301            trie.reveal_nodes(vec![RevealedSparseNode { path, node, masks }]).unwrap();
3302
3303            // Check that the lower subtrie was created
3304            let idx = path_subtrie_index_unchecked(&path);
3305            assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
3306
3307            // Check that the lower subtrie's path was correctly set
3308            let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
3309            assert_eq!(lower_subtrie.path, path);
3310
3311            assert_matches!(
3312                lower_subtrie.nodes.get(&path),
3313                Some(SparseNode::Leaf { key, hash: None })
3314                if key == &Nibbles::from_nibbles([0x3, 0x4])
3315            );
3316        }
3317
3318        // Reveal leaf in a lower trie with a longer path, shouldn't result in the subtrie's root
3319        // path changing.
3320        {
3321            let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
3322            let node = create_leaf_node([0x4, 0x5], 42);
3323            let masks = TrieMasks::none();
3324
3325            trie.reveal_nodes(vec![RevealedSparseNode { path, node, masks }]).unwrap();
3326
3327            // Check that the lower subtrie's path hasn't changed
3328            let idx = path_subtrie_index_unchecked(&path);
3329            let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
3330            assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2]));
3331        }
3332    }
3333
3334    #[test]
3335    fn test_reveal_node_extension_all_upper() {
3336        let path = Nibbles::new();
3337        let child_hash = B256::repeat_byte(0xab);
3338        let node = create_extension_node([0x1], child_hash);
3339        let masks = TrieMasks::none();
3340        let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
3341
3342        assert_matches!(
3343            trie.upper_subtrie.nodes.get(&path),
3344            Some(SparseNode::Extension { key, hash: None, .. })
3345            if key == &Nibbles::from_nibbles([0x1])
3346        );
3347
3348        // Child path should be in upper trie
3349        let child_path = Nibbles::from_nibbles([0x1]);
3350        assert_eq!(trie.upper_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
3351    }
3352
3353    #[test]
3354    fn test_reveal_node_extension_cross_level() {
3355        let path = Nibbles::new();
3356        let child_hash = B256::repeat_byte(0xcd);
3357        let node = create_extension_node([0x1, 0x2, 0x3], child_hash);
3358        let masks = TrieMasks::none();
3359        let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
3360
3361        // Extension node should be in upper trie
3362        assert_matches!(
3363            trie.upper_subtrie.nodes.get(&path),
3364            Some(SparseNode::Extension { key, hash: None, .. })
3365            if key == &Nibbles::from_nibbles([0x1, 0x2, 0x3])
3366        );
3367
3368        // Child path (0x1, 0x2, 0x3) should be in lower trie
3369        let child_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
3370        let idx = path_subtrie_index_unchecked(&child_path);
3371        assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
3372
3373        let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
3374        assert_eq!(lower_subtrie.path, child_path);
3375        assert_eq!(lower_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
3376    }
3377
3378    #[test]
3379    fn test_reveal_node_extension_cross_level_boundary() {
3380        let mut trie = ParallelSparseTrie::default();
3381        let path = Nibbles::from_nibbles([0x1]);
3382        let child_hash = B256::repeat_byte(0xcd);
3383        let node = create_extension_node([0x2], child_hash);
3384        let masks = TrieMasks::none();
3385
3386        trie.reveal_nodes(vec![RevealedSparseNode { path, node, masks }]).unwrap();
3387
3388        // Extension node should be in upper trie
3389        assert_matches!(
3390            trie.upper_subtrie.nodes.get(&path),
3391            Some(SparseNode::Extension { key, hash: None, .. })
3392            if key == &Nibbles::from_nibbles([0x2])
3393        );
3394
3395        // Child path (0x1, 0x2) should be in lower trie
3396        let child_path = Nibbles::from_nibbles([0x1, 0x2]);
3397        let idx = path_subtrie_index_unchecked(&child_path);
3398        assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
3399
3400        let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
3401        assert_eq!(lower_subtrie.path, child_path);
3402        assert_eq!(lower_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
3403    }
3404
3405    #[test]
3406    fn test_reveal_node_branch_all_upper() {
3407        let path = Nibbles::new();
3408        let child_hashes = [
3409            RlpNode::word_rlp(&B256::repeat_byte(0x11)),
3410            RlpNode::word_rlp(&B256::repeat_byte(0x22)),
3411        ];
3412        let node = create_branch_node_with_children(&[0x0, 0x5], child_hashes.clone());
3413        let masks = TrieMasks::none();
3414        let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
3415
3416        // Branch node should be in upper trie
3417        assert_matches!(
3418            trie.upper_subtrie.nodes.get(&path),
3419            Some(SparseNode::Branch { state_mask, hash: None, .. })
3420            if *state_mask == 0b0000000000100001.into()
3421        );
3422
3423        // Children should be in upper trie (paths of length 2)
3424        let child_path_0 = Nibbles::from_nibbles([0x0]);
3425        let child_path_5 = Nibbles::from_nibbles([0x5]);
3426        assert_eq!(
3427            trie.upper_subtrie.nodes.get(&child_path_0),
3428            Some(&SparseNode::Hash(child_hashes[0].as_hash().unwrap()))
3429        );
3430        assert_eq!(
3431            trie.upper_subtrie.nodes.get(&child_path_5),
3432            Some(&SparseNode::Hash(child_hashes[1].as_hash().unwrap()))
3433        );
3434    }
3435
3436    #[test]
3437    fn test_reveal_node_branch_cross_level() {
3438        let mut trie = ParallelSparseTrie::default();
3439        let path = Nibbles::from_nibbles([0x1]); // Exactly 1 nibbles - boundary case
3440        let child_hashes = [
3441            RlpNode::word_rlp(&B256::repeat_byte(0x33)),
3442            RlpNode::word_rlp(&B256::repeat_byte(0x44)),
3443            RlpNode::word_rlp(&B256::repeat_byte(0x55)),
3444        ];
3445        let node = create_branch_node_with_children(&[0x0, 0x7, 0xf], child_hashes.clone());
3446        let masks = TrieMasks::none();
3447
3448        trie.reveal_nodes(vec![RevealedSparseNode { path, node, masks }]).unwrap();
3449
3450        // Branch node should be in upper trie
3451        assert_matches!(
3452            trie.upper_subtrie.nodes.get(&path),
3453            Some(SparseNode::Branch { state_mask, hash: None, .. })
3454            if *state_mask == 0b1000000010000001.into()
3455        );
3456
3457        // All children should be in lower tries since they have paths of length 3
3458        let child_paths = [
3459            Nibbles::from_nibbles([0x1, 0x0]),
3460            Nibbles::from_nibbles([0x1, 0x7]),
3461            Nibbles::from_nibbles([0x1, 0xf]),
3462        ];
3463
3464        for (i, child_path) in child_paths.iter().enumerate() {
3465            let idx = path_subtrie_index_unchecked(child_path);
3466            let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
3467            assert_eq!(&lower_subtrie.path, child_path);
3468            assert_eq!(
3469                lower_subtrie.nodes.get(child_path),
3470                Some(&SparseNode::Hash(child_hashes[i].as_hash().unwrap())),
3471            );
3472        }
3473    }
3474
3475    #[test]
3476    fn test_update_subtrie_hashes_prefix_set_matching() {
3477        // Create a trie and reveal leaf nodes using reveal_nodes
3478        let mut trie = ParallelSparseTrie::default();
3479
3480        // Create dummy leaf nodes.
3481        let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
3482        let leaf_1_path = leaf_1_full_path.slice(..2);
3483        let leaf_1_key = leaf_1_full_path.slice(2..);
3484        let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 1], vec![0; 62]].concat());
3485        let leaf_2_path = leaf_2_full_path.slice(..2);
3486        let leaf_2_key = leaf_2_full_path.slice(2..);
3487        let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 2], vec![0; 62]].concat());
3488        let leaf_3_path = leaf_3_full_path.slice(..2);
3489        let leaf_3_key = leaf_3_full_path.slice(2..);
3490        let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), 1);
3491        let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), 2);
3492        let leaf_3 = create_leaf_node(leaf_3_key.to_vec(), 3);
3493
3494        // Create branch node with hashes for each leaf.
3495        let child_hashes = [
3496            RlpNode::word_rlp(&B256::repeat_byte(0x00)),
3497            RlpNode::word_rlp(&B256::repeat_byte(0x11)),
3498            // deliberately omit hash for leaf_3
3499        ];
3500        let branch_path = Nibbles::from_nibbles([0x0]);
3501        let branch_node = create_branch_node_with_children(&[0x0, 0x1, 0x2], child_hashes);
3502
3503        // Reveal nodes using reveal_nodes
3504        trie.reveal_nodes(vec![
3505            RevealedSparseNode { path: branch_path, node: branch_node, masks: TrieMasks::none() },
3506            RevealedSparseNode { path: leaf_1_path, node: leaf_1, masks: TrieMasks::none() },
3507            RevealedSparseNode { path: leaf_2_path, node: leaf_2, masks: TrieMasks::none() },
3508            RevealedSparseNode { path: leaf_3_path, node: leaf_3, masks: TrieMasks::none() },
3509        ])
3510        .unwrap();
3511
3512        // Calculate subtrie indexes
3513        let subtrie_1_index = SparseSubtrieType::from_path(&leaf_1_path).lower_index().unwrap();
3514        let subtrie_2_index = SparseSubtrieType::from_path(&leaf_2_path).lower_index().unwrap();
3515        let subtrie_3_index = SparseSubtrieType::from_path(&leaf_3_path).lower_index().unwrap();
3516
3517        let mut unchanged_prefix_set = PrefixSetMut::from([
3518            Nibbles::from_nibbles([0x0]),
3519            leaf_2_full_path,
3520            Nibbles::from_nibbles([0x3, 0x0, 0x0]),
3521        ]);
3522        // Create a prefix set with the keys that match only the second subtrie
3523        let mut prefix_set = PrefixSetMut::from([
3524            // Match second subtrie
3525            Nibbles::from_nibbles([0x0, 0x1, 0x0]),
3526            Nibbles::from_nibbles([0x0, 0x1, 0x1, 0x0]),
3527        ]);
3528        prefix_set.extend(unchanged_prefix_set.clone());
3529        trie.prefix_set = prefix_set;
3530
3531        // Update subtrie hashes
3532        trie.update_subtrie_hashes();
3533
3534        // We expect that leaf 3 (0x02) should have been added to the prefix set, because it is
3535        // missing a hash and is the root node of a lower subtrie, and therefore would need to have
3536        // that hash calculated by `update_upper_subtrie_hashes`.
3537        unchanged_prefix_set.insert(leaf_3_full_path);
3538
3539        // Check that the prefix set was updated
3540        assert_eq!(
3541            trie.prefix_set.clone().freeze().into_iter().collect::<Vec<_>>(),
3542            unchanged_prefix_set.freeze().into_iter().collect::<Vec<_>>()
3543        );
3544        // Check that subtries were returned back to the array
3545        assert!(trie.lower_subtries[subtrie_1_index].as_revealed_ref().is_some());
3546        assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_some());
3547        assert!(trie.lower_subtries[subtrie_3_index].as_revealed_ref().is_some());
3548    }
3549
3550    #[test]
3551    fn test_subtrie_update_hashes() {
3552        let mut subtrie = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
3553
3554        // Create leaf nodes with paths 0x0...0, 0x00001...0, 0x0010...0
3555        let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
3556        let leaf_1_path = leaf_1_full_path.slice(..5);
3557        let leaf_1_key = leaf_1_full_path.slice(5..);
3558        let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 0, 0, 0, 1], vec![0; 59]].concat());
3559        let leaf_2_path = leaf_2_full_path.slice(..5);
3560        let leaf_2_key = leaf_2_full_path.slice(5..);
3561        let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 0, 1], vec![0; 61]].concat());
3562        let leaf_3_path = leaf_3_full_path.slice(..3);
3563        let leaf_3_key = leaf_3_full_path.slice(3..);
3564
3565        let account_1 = create_account(1);
3566        let account_2 = create_account(2);
3567        let account_3 = create_account(3);
3568        let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
3569        let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
3570        let leaf_3 = create_leaf_node(leaf_3_key.to_vec(), account_3.nonce);
3571
3572        // Create bottom branch node
3573        let branch_1_path = Nibbles::from_nibbles([0, 0, 0, 0]);
3574        let branch_1 = create_branch_node_with_children(
3575            &[0, 1],
3576            vec![
3577                RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
3578                RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
3579            ],
3580        );
3581
3582        // Create an extension node
3583        let extension_path = Nibbles::from_nibbles([0, 0, 0]);
3584        let extension_key = Nibbles::from_nibbles([0]);
3585        let extension = create_extension_node(
3586            extension_key.to_vec(),
3587            RlpNode::from_rlp(&alloy_rlp::encode(&branch_1)).as_hash().unwrap(),
3588        );
3589
3590        // Create top branch node
3591        let branch_2_path = Nibbles::from_nibbles([0, 0]);
3592        let branch_2 = create_branch_node_with_children(
3593            &[0, 1],
3594            vec![
3595                RlpNode::from_rlp(&alloy_rlp::encode(&extension)),
3596                RlpNode::from_rlp(&alloy_rlp::encode(&leaf_3)),
3597            ],
3598        );
3599
3600        // Reveal nodes
3601        subtrie.reveal_node(branch_2_path, &branch_2, TrieMasks::none()).unwrap();
3602        subtrie.reveal_node(leaf_1_path, &leaf_1, TrieMasks::none()).unwrap();
3603        subtrie.reveal_node(extension_path, &extension, TrieMasks::none()).unwrap();
3604        subtrie.reveal_node(branch_1_path, &branch_1, TrieMasks::none()).unwrap();
3605        subtrie.reveal_node(leaf_2_path, &leaf_2, TrieMasks::none()).unwrap();
3606        subtrie.reveal_node(leaf_3_path, &leaf_3, TrieMasks::none()).unwrap();
3607
3608        // Run hash builder for two leaf nodes
3609        let (_, _, proof_nodes, _, _) = run_hash_builder(
3610            [
3611                (leaf_1_full_path, account_1),
3612                (leaf_2_full_path, account_2),
3613                (leaf_3_full_path, account_3),
3614            ],
3615            NoopAccountTrieCursor::default(),
3616            Default::default(),
3617            [
3618                branch_1_path,
3619                extension_path,
3620                branch_2_path,
3621                leaf_1_full_path,
3622                leaf_2_full_path,
3623                leaf_3_full_path,
3624            ],
3625        );
3626
3627        // Update hashes for the subtrie
3628        subtrie.update_hashes(
3629            &mut PrefixSetMut::from([leaf_1_full_path, leaf_2_full_path, leaf_3_full_path])
3630                .freeze(),
3631            &mut None,
3632            &HashMap::default(),
3633            &HashMap::default(),
3634        );
3635
3636        // Compare hashes between hash builder and subtrie
3637        let hash_builder_branch_1_hash =
3638            RlpNode::from_rlp(proof_nodes.get(&branch_1_path).unwrap().as_ref()).as_hash().unwrap();
3639        let subtrie_branch_1_hash = subtrie.nodes.get(&branch_1_path).unwrap().hash().unwrap();
3640        assert_eq!(hash_builder_branch_1_hash, subtrie_branch_1_hash);
3641
3642        let hash_builder_extension_hash =
3643            RlpNode::from_rlp(proof_nodes.get(&extension_path).unwrap().as_ref())
3644                .as_hash()
3645                .unwrap();
3646        let subtrie_extension_hash = subtrie.nodes.get(&extension_path).unwrap().hash().unwrap();
3647        assert_eq!(hash_builder_extension_hash, subtrie_extension_hash);
3648
3649        let hash_builder_branch_2_hash =
3650            RlpNode::from_rlp(proof_nodes.get(&branch_2_path).unwrap().as_ref()).as_hash().unwrap();
3651        let subtrie_branch_2_hash = subtrie.nodes.get(&branch_2_path).unwrap().hash().unwrap();
3652        assert_eq!(hash_builder_branch_2_hash, subtrie_branch_2_hash);
3653
3654        let subtrie_leaf_1_hash = subtrie.nodes.get(&leaf_1_path).unwrap().hash().unwrap();
3655        let hash_builder_leaf_1_hash =
3656            RlpNode::from_rlp(proof_nodes.get(&leaf_1_path).unwrap().as_ref()).as_hash().unwrap();
3657        assert_eq!(hash_builder_leaf_1_hash, subtrie_leaf_1_hash);
3658
3659        let hash_builder_leaf_2_hash =
3660            RlpNode::from_rlp(proof_nodes.get(&leaf_2_path).unwrap().as_ref()).as_hash().unwrap();
3661        let subtrie_leaf_2_hash = subtrie.nodes.get(&leaf_2_path).unwrap().hash().unwrap();
3662        assert_eq!(hash_builder_leaf_2_hash, subtrie_leaf_2_hash);
3663
3664        let hash_builder_leaf_3_hash =
3665            RlpNode::from_rlp(proof_nodes.get(&leaf_3_path).unwrap().as_ref()).as_hash().unwrap();
3666        let subtrie_leaf_3_hash = subtrie.nodes.get(&leaf_3_path).unwrap().hash().unwrap();
3667        assert_eq!(hash_builder_leaf_3_hash, subtrie_leaf_3_hash);
3668    }
3669
3670    #[test]
3671    fn test_remove_leaf_branch_becomes_extension() {
3672        //
3673        // 0x:      Extension (Key = 5)
3674        // 0x5:     └── Branch (Mask = 1001)
3675        // 0x50:        ├── 0 -> Extension (Key = 23)
3676        // 0x5023:      │        └── Branch (Mask = 0101)
3677        // 0x50231:     │            ├── 1 -> Leaf
3678        // 0x50233:     │            └── 3 -> Leaf
3679        // 0x53:        └── 3 -> Leaf (Key = 7)
3680        //
3681        // After removing 0x53, extension+branch+extension become a single extension
3682        //
3683        let mut trie = new_test_trie(
3684            [
3685                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
3686                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b1001))),
3687                (
3688                    Nibbles::from_nibbles([0x5, 0x0]),
3689                    SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3])),
3690                ),
3691                (
3692                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
3693                    SparseNode::new_branch(TrieMask::new(0b0101)),
3694                ),
3695                (
3696                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
3697                    SparseNode::new_leaf(Nibbles::new()),
3698                ),
3699                (
3700                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
3701                    SparseNode::new_leaf(Nibbles::new()),
3702                ),
3703                (
3704                    Nibbles::from_nibbles([0x5, 0x3]),
3705                    SparseNode::new_leaf(Nibbles::from_nibbles([0x7])),
3706                ),
3707            ]
3708            .into_iter(),
3709        );
3710
3711        let provider = MockTrieNodeProvider::new();
3712
3713        // Remove the leaf with a full path of 0x537
3714        let leaf_full_path = Nibbles::from_nibbles([0x5, 0x3, 0x7]);
3715        trie.remove_leaf(&leaf_full_path, provider).unwrap();
3716
3717        let upper_subtrie = &trie.upper_subtrie;
3718        let lower_subtrie_50 = trie.lower_subtries[0x50].as_revealed_ref().unwrap();
3719
3720        // Check that the `SparseSubtrie` the leaf was removed from was itself removed, as it is now
3721        // empty.
3722        assert_matches!(trie.lower_subtries[0x53].as_revealed_ref(), None);
3723
3724        // Check that the leaf node was removed, and that its parent/grandparent were modified
3725        // appropriately.
3726        assert_matches!(
3727            upper_subtrie.nodes.get(&Nibbles::from_nibbles([])),
3728            Some(SparseNode::Extension{ key, ..})
3729            if key == &Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])
3730        );
3731        assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
3732        assert_matches!(lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0])), None);
3733        assert_matches!(
3734            lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])),
3735            Some(SparseNode::Branch{ state_mask, .. })
3736            if *state_mask == 0b0101.into()
3737        );
3738    }
3739
3740    #[test]
3741    fn test_remove_leaf_branch_becomes_leaf() {
3742        //
3743        // 0x:      Branch (Mask = 0011)
3744        // 0x0:     ├── 0 -> Leaf (Key = 12)
3745        // 0x1:     └── 1 -> Leaf (Key = 34)
3746        //
3747        // After removing 0x012, branch becomes a leaf
3748        //
3749        let mut trie = new_test_trie(
3750            [
3751                (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0011))),
3752                (
3753                    Nibbles::from_nibbles([0x0]),
3754                    SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
3755                ),
3756                (
3757                    Nibbles::from_nibbles([0x1]),
3758                    SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
3759                ),
3760            ]
3761            .into_iter(),
3762        );
3763
3764        // Add the branch node to updated_nodes to simulate it being modified earlier
3765        if let Some(updates) = trie.updates.as_mut() {
3766            updates
3767                .updated_nodes
3768                .insert(Nibbles::default(), BranchNodeCompact::new(0b11, 0, 0, vec![], None));
3769        }
3770
3771        let provider = MockTrieNodeProvider::new();
3772
3773        // Remove the leaf with a full path of 0x012
3774        let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2]);
3775        trie.remove_leaf(&leaf_full_path, provider).unwrap();
3776
3777        let upper_subtrie = &trie.upper_subtrie;
3778
3779        // Check that the leaf's value was removed
3780        assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
3781
3782        // Check that the branch node collapsed into a leaf node with the remaining child's key
3783        assert_matches!(
3784            upper_subtrie.nodes.get(&Nibbles::default()),
3785            Some(SparseNode::Leaf{ key, ..})
3786            if key == &Nibbles::from_nibbles([0x1, 0x3, 0x4])
3787        );
3788
3789        // Check that the remaining child node was removed
3790        assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
3791        // Check that the removed child node was also removed
3792        assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])), None);
3793
3794        // Check that updates were tracked correctly when branch collapsed
3795        let updates = trie.updates.as_ref().unwrap();
3796
3797        // The branch at root should be marked as removed since it collapsed
3798        assert!(updates.removed_nodes.contains(&Nibbles::default()));
3799
3800        // The branch should no longer be in updated_nodes
3801        assert!(!updates.updated_nodes.contains_key(&Nibbles::default()));
3802    }
3803
3804    #[test]
3805    fn test_remove_leaf_extension_becomes_leaf() {
3806        //
3807        // 0x:      Extension (Key = 5)
3808        // 0x5:     └── Branch (Mask = 0011)
3809        // 0x50:        ├── 0 -> Leaf (Key = 12)
3810        // 0x51:        └── 1 -> Leaf (Key = 34)
3811        //
3812        // After removing 0x5012, extension+branch becomes a leaf
3813        //
3814        let mut trie = new_test_trie(
3815            [
3816                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
3817                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b0011))),
3818                (
3819                    Nibbles::from_nibbles([0x5, 0x0]),
3820                    SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
3821                ),
3822                (
3823                    Nibbles::from_nibbles([0x5, 0x1]),
3824                    SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
3825                ),
3826            ]
3827            .into_iter(),
3828        );
3829
3830        let provider = MockTrieNodeProvider::new();
3831
3832        // Remove the leaf with a full path of 0x5012
3833        let leaf_full_path = Nibbles::from_nibbles([0x5, 0x0, 0x1, 0x2]);
3834        trie.remove_leaf(&leaf_full_path, provider).unwrap();
3835
3836        let upper_subtrie = &trie.upper_subtrie;
3837
3838        // Check that both lower subtries were removed. 0x50 should have been removed because
3839        // removing its leaf made it empty. 0x51 should have been removed after its own leaf was
3840        // collapsed into the upper trie, leaving it also empty.
3841        assert_matches!(trie.lower_subtries[0x50].as_revealed_ref(), None);
3842        assert_matches!(trie.lower_subtries[0x51].as_revealed_ref(), None);
3843
3844        // Check that the other leaf's value was moved to the upper trie
3845        let other_leaf_full_value = Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4]);
3846        assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
3847
3848        // Check that the extension node collapsed into a leaf node
3849        assert_matches!(
3850            upper_subtrie.nodes.get(&Nibbles::default()),
3851            Some(SparseNode::Leaf{ key, ..})
3852            if key == &Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4])
3853        );
3854
3855        // Check that intermediate nodes were removed
3856        assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
3857    }
3858
3859    #[test]
3860    fn test_remove_leaf_branch_on_branch() {
3861        //
3862        // 0x:      Branch (Mask = 0101)
3863        // 0x0:     ├── 0 -> Leaf (Key = 12)
3864        // 0x2:     └── 2 -> Branch (Mask = 0011)
3865        // 0x20:        ├── 0 -> Leaf (Key = 34)
3866        // 0x21:        └── 1 -> Leaf (Key = 56)
3867        //
3868        // After removing 0x2034, the inner branch becomes a leaf
3869        //
3870        let mut trie = new_test_trie(
3871            [
3872                (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0101))),
3873                (
3874                    Nibbles::from_nibbles([0x0]),
3875                    SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
3876                ),
3877                (Nibbles::from_nibbles([0x2]), SparseNode::new_branch(TrieMask::new(0b0011))),
3878                (
3879                    Nibbles::from_nibbles([0x2, 0x0]),
3880                    SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
3881                ),
3882                (
3883                    Nibbles::from_nibbles([0x2, 0x1]),
3884                    SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x6])),
3885                ),
3886            ]
3887            .into_iter(),
3888        );
3889
3890        let provider = MockTrieNodeProvider::new();
3891
3892        // Remove the leaf with a full path of 0x2034
3893        let leaf_full_path = Nibbles::from_nibbles([0x2, 0x0, 0x3, 0x4]);
3894        trie.remove_leaf(&leaf_full_path, provider).unwrap();
3895
3896        let upper_subtrie = &trie.upper_subtrie;
3897
3898        // Check that both lower subtries were removed. 0x20 should have been removed because
3899        // removing its leaf made it empty. 0x21 should have been removed after its own leaf was
3900        // collapsed into the upper trie, leaving it also empty.
3901        assert_matches!(trie.lower_subtries[0x20].as_revealed_ref(), None);
3902        assert_matches!(trie.lower_subtries[0x21].as_revealed_ref(), None);
3903
3904        // Check that the other leaf's value was moved to the upper trie
3905        let other_leaf_full_value = Nibbles::from_nibbles([0x2, 0x1, 0x5, 0x6]);
3906        assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
3907
3908        // Check that the root branch still exists unchanged
3909        assert_matches!(
3910            upper_subtrie.nodes.get(&Nibbles::default()),
3911            Some(SparseNode::Branch{ state_mask, .. })
3912            if *state_mask == 0b0101.into()
3913        );
3914
3915        // Check that the inner branch became an extension
3916        assert_matches!(
3917            upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x2])),
3918            Some(SparseNode::Leaf{ key, ..})
3919            if key == &Nibbles::from_nibbles([0x1, 0x5, 0x6])
3920        );
3921    }
3922
3923    #[test]
3924    fn test_remove_leaf_lower_subtrie_root_path_update() {
3925        //
3926        // 0x:        Extension (Key = 123, root of lower subtrie)
3927        // 0x123:     └── Branch (Mask = 0011000)
3928        // 0x1233:        ├── 3 -> Leaf (Key = [])
3929        // 0x1234:        └── 4 -> Extension (Key = 5)
3930        // 0x12345:           └── Branch (Mask = 0011)
3931        // 0x123450:              ├── 0 -> Leaf (Key = [])
3932        // 0x123451:              └── 1 -> Leaf (Key = [])
3933        //
3934        // After removing leaf at 0x1233, the branch at 0x123 becomes an extension to 0x12345, which
3935        // then gets merged with the root extension at 0x. The lower subtrie's `path` field should
3936        // be updated from 0x123 to 0x12345.
3937        //
3938        let mut trie = new_test_trie(
3939            [
3940                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x1, 0x2, 0x3]))),
3941                (
3942                    Nibbles::from_nibbles([0x1, 0x2, 0x3]),
3943                    SparseNode::new_branch(TrieMask::new(0b0011000)),
3944                ),
3945                (
3946                    Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]),
3947                    SparseNode::new_leaf(Nibbles::default()),
3948                ),
3949                (
3950                    Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]),
3951                    SparseNode::new_ext(Nibbles::from_nibbles([0x5])),
3952                ),
3953                (
3954                    Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]),
3955                    SparseNode::new_branch(TrieMask::new(0b0011)),
3956                ),
3957                (
3958                    Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x0]),
3959                    SparseNode::new_leaf(Nibbles::default()),
3960                ),
3961                (
3962                    Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x1]),
3963                    SparseNode::new_leaf(Nibbles::default()),
3964                ),
3965            ]
3966            .into_iter(),
3967        );
3968
3969        let provider = MockTrieNodeProvider::new();
3970
3971        // Verify initial state - the lower subtrie's path should be 0x123
3972        let lower_subtrie_root_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
3973        assert_matches!(
3974            trie.lower_subtrie_for_path_mut(&lower_subtrie_root_path),
3975            Some(subtrie)
3976            if subtrie.path == lower_subtrie_root_path
3977        );
3978
3979        // Remove the leaf at 0x1233
3980        let leaf_full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]);
3981        trie.remove_leaf(&leaf_full_path, provider).unwrap();
3982
3983        // After removal:
3984        // 1. The branch at 0x123 should become an extension to 0x12345
3985        // 2. That extension should merge with the root extension at 0x
3986        // 3. The lower subtrie's path should be updated to 0x12345
3987        let lower_subtrie = trie.lower_subtries[0x12].as_revealed_ref().unwrap();
3988        assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]));
3989
3990        // Verify the root extension now points all the way to 0x12345
3991        assert_matches!(
3992            trie.upper_subtrie.nodes.get(&Nibbles::default()),
3993            Some(SparseNode::Extension { key, .. })
3994            if key == &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])
3995        );
3996
3997        // Verify the branch at 0x12345 hasn't been modified
3998        assert_matches!(
3999            lower_subtrie.nodes.get(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])),
4000            Some(SparseNode::Branch { state_mask, .. })
4001            if state_mask == &TrieMask::new(0b0011)
4002        );
4003    }
4004
4005    #[test]
4006    fn test_remove_leaf_remaining_child_needs_reveal() {
4007        //
4008        // 0x:      Branch (Mask = 0011)
4009        // 0x0:     ├── 0 -> Leaf (Key = 12)
4010        // 0x1:     └── 1 -> Hash (blinded leaf)
4011        //
4012        // After removing 0x012, the hash node needs to be revealed to collapse the branch
4013        //
4014        let mut trie = new_test_trie(
4015            [
4016                (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0011))),
4017                (
4018                    Nibbles::from_nibbles([0x0]),
4019                    SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
4020                ),
4021                (Nibbles::from_nibbles([0x1]), SparseNode::Hash(B256::repeat_byte(0xab))),
4022            ]
4023            .into_iter(),
4024        );
4025
4026        // Create a mock provider that will reveal the blinded leaf
4027        let mut provider = MockTrieNodeProvider::new();
4028        let revealed_leaf = create_leaf_node([0x3, 0x4], 42);
4029        let mut encoded = Vec::new();
4030        revealed_leaf.encode(&mut encoded);
4031        provider.add_revealed_node(
4032            Nibbles::from_nibbles([0x1]),
4033            RevealedNode { node: encoded.into(), tree_mask: None, hash_mask: None },
4034        );
4035
4036        // Remove the leaf with a full path of 0x012
4037        let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2]);
4038        trie.remove_leaf(&leaf_full_path, provider).unwrap();
4039
4040        let upper_subtrie = &trie.upper_subtrie;
4041
4042        // Check that the leaf value was removed
4043        assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4044
4045        // Check that the branch node collapsed into a leaf node with the revealed child's key
4046        assert_matches!(
4047            upper_subtrie.nodes.get(&Nibbles::default()),
4048            Some(SparseNode::Leaf{ key, ..})
4049            if key == &Nibbles::from_nibbles([0x1, 0x3, 0x4])
4050        );
4051
4052        // Check that the remaining child node was removed (since it was merged)
4053        assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
4054    }
4055
4056    #[test]
4057    fn test_remove_leaf_root() {
4058        //
4059        // 0x:      Leaf (Key = 123)
4060        //
4061        // After removing 0x123, the trie becomes empty
4062        //
4063        let mut trie = new_test_trie(std::iter::once((
4064            Nibbles::default(),
4065            SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2, 0x3])),
4066        )));
4067
4068        let provider = MockTrieNodeProvider::new();
4069
4070        // Remove the leaf with a full key of 0x123
4071        let leaf_full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4072        trie.remove_leaf(&leaf_full_path, provider).unwrap();
4073
4074        let upper_subtrie = &trie.upper_subtrie;
4075
4076        // Check that the leaf value was removed
4077        assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4078
4079        // Check that the root node was changed to Empty
4080        assert_matches!(upper_subtrie.nodes.get(&Nibbles::default()), Some(SparseNode::Empty));
4081    }
4082
4083    #[test]
4084    fn test_remove_leaf_unsets_hash_along_path() {
4085        //
4086        // Creates a trie structure:
4087        // 0x:      Branch (with hash set)
4088        // 0x0:     ├── Extension (with hash set)
4089        // 0x01:    │   └── Branch (with hash set)
4090        // 0x012:   │       ├── Leaf (Key = 34, with hash set)
4091        // 0x013:   │       ├── Leaf (Key = 56, with hash set)
4092        // 0x014:   │       └── Leaf (Key = 78, with hash set)
4093        // 0x1:     └── Leaf (Key = 78, with hash set)
4094        //
4095        // When removing leaf at 0x01234, all nodes along the path (root branch,
4096        // extension at 0x0, branch at 0x01) should have their hash field unset
4097        //
4098
4099        let mut trie = new_test_trie(
4100            [
4101                (
4102                    Nibbles::default(),
4103                    SparseNode::Branch {
4104                        state_mask: TrieMask::new(0b0011),
4105                        hash: Some(B256::repeat_byte(0x10)),
4106                        store_in_db_trie: None,
4107                    },
4108                ),
4109                (
4110                    Nibbles::from_nibbles([0x0]),
4111                    SparseNode::Extension {
4112                        key: Nibbles::from_nibbles([0x1]),
4113                        hash: Some(B256::repeat_byte(0x20)),
4114                        store_in_db_trie: None,
4115                    },
4116                ),
4117                (
4118                    Nibbles::from_nibbles([0x0, 0x1]),
4119                    SparseNode::Branch {
4120                        state_mask: TrieMask::new(0b11100),
4121                        hash: Some(B256::repeat_byte(0x30)),
4122                        store_in_db_trie: None,
4123                    },
4124                ),
4125                (
4126                    Nibbles::from_nibbles([0x0, 0x1, 0x2]),
4127                    SparseNode::Leaf {
4128                        key: Nibbles::from_nibbles([0x3, 0x4]),
4129                        hash: Some(B256::repeat_byte(0x40)),
4130                    },
4131                ),
4132                (
4133                    Nibbles::from_nibbles([0x0, 0x1, 0x3]),
4134                    SparseNode::Leaf {
4135                        key: Nibbles::from_nibbles([0x5, 0x6]),
4136                        hash: Some(B256::repeat_byte(0x50)),
4137                    },
4138                ),
4139                (
4140                    Nibbles::from_nibbles([0x0, 0x1, 0x4]),
4141                    SparseNode::Leaf {
4142                        key: Nibbles::from_nibbles([0x6, 0x7]),
4143                        hash: Some(B256::repeat_byte(0x60)),
4144                    },
4145                ),
4146                (
4147                    Nibbles::from_nibbles([0x1]),
4148                    SparseNode::Leaf {
4149                        key: Nibbles::from_nibbles([0x7, 0x8]),
4150                        hash: Some(B256::repeat_byte(0x70)),
4151                    },
4152                ),
4153            ]
4154            .into_iter(),
4155        );
4156
4157        let provider = MockTrieNodeProvider::new();
4158
4159        // Remove a leaf which does not exist; this should have no effect.
4160        trie.remove_leaf(&Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4, 0xF]), &provider)
4161            .unwrap();
4162        for (path, node) in trie.all_nodes() {
4163            assert!(node.hash().is_some(), "path {path:?} should still have a hash");
4164        }
4165
4166        // Remove the leaf at path 0x01234
4167        let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4]);
4168        trie.remove_leaf(&leaf_full_path, &provider).unwrap();
4169
4170        let upper_subtrie = &trie.upper_subtrie;
4171        let lower_subtrie_10 = trie.lower_subtries[0x01].as_revealed_ref().unwrap();
4172
4173        // Verify that hash fields are unset for all nodes along the path to the removed leaf
4174        assert_matches!(
4175            upper_subtrie.nodes.get(&Nibbles::default()),
4176            Some(SparseNode::Branch { hash: None, .. })
4177        );
4178        assert_matches!(
4179            upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])),
4180            Some(SparseNode::Extension { hash: None, .. })
4181        );
4182        assert_matches!(
4183            lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1])),
4184            Some(SparseNode::Branch { hash: None, .. })
4185        );
4186
4187        // Verify that nodes not on the path still have their hashes
4188        assert_matches!(
4189            upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])),
4190            Some(SparseNode::Leaf { hash: Some(_), .. })
4191        );
4192        assert_matches!(
4193            lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x3])),
4194            Some(SparseNode::Leaf { hash: Some(_), .. })
4195        );
4196        assert_matches!(
4197            lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x4])),
4198            Some(SparseNode::Leaf { hash: Some(_), .. })
4199        );
4200    }
4201
4202    #[test]
4203    fn test_remove_leaf_remaining_extension_node_child_is_revealed() {
4204        let branch_path = Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7]);
4205        let removed_branch_path = Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2]);
4206
4207        // Convert the logs into reveal_nodes call on a fresh ParallelSparseTrie
4208        let nodes = vec![
4209            // Branch at 0x4f8807
4210            RevealedSparseNode {
4211                path: branch_path,
4212                node: {
4213                    TrieNode::Branch(BranchNode::new(
4214                        vec![
4215                            RlpNode::word_rlp(&B256::from(hex!(
4216                                "dede882d52f0e0eddfb5b89293a10c87468b4a73acd0d4ae550054a92353f6d5"
4217                            ))),
4218                            RlpNode::word_rlp(&B256::from(hex!(
4219                                "8746f18e465e2eed16117306b6f2eef30bc9d2978aee4a7838255e39c41a3222"
4220                            ))),
4221                            RlpNode::word_rlp(&B256::from(hex!(
4222                                "35a4ea861548af5f0262a9b6d619b4fc88fce6531cbd004eab1530a73f34bbb1"
4223                            ))),
4224                            RlpNode::word_rlp(&B256::from(hex!(
4225                                "47d5c2bf9eea5c1ee027e4740c2b86159074a27d52fd2f6a8a8c86c77e48006f"
4226                            ))),
4227                            RlpNode::word_rlp(&B256::from(hex!(
4228                                "eb76a359b216e1d86b1f2803692a9fe8c3d3f97a9fe6a82b396e30344febc0c1"
4229                            ))),
4230                            RlpNode::word_rlp(&B256::from(hex!(
4231                                "437656f2697f167b23e33cb94acc8550128cfd647fc1579d61e982cb7616b8bc"
4232                            ))),
4233                            RlpNode::word_rlp(&B256::from(hex!(
4234                                "45a1ac2faf15ea8a4da6f921475974e0379f39c3d08166242255a567fa88ce6c"
4235                            ))),
4236                            RlpNode::word_rlp(&B256::from(hex!(
4237                                "7dbb299d714d3dfa593f53bc1b8c66d5c401c30a0b5587b01254a56330361395"
4238                            ))),
4239                            RlpNode::word_rlp(&B256::from(hex!(
4240                                "ae407eb14a74ed951c9949c1867fb9ee9ba5d5b7e03769eaf3f29c687d080429"
4241                            ))),
4242                            RlpNode::word_rlp(&B256::from(hex!(
4243                                "768d0fe1003f0e85d3bc76e4a1fa0827f63b10ca9bca52d56c2b1cceb8eb8b08"
4244                            ))),
4245                            RlpNode::word_rlp(&B256::from(hex!(
4246                                "e5127935143493d5094f4da6e4f7f5a0f62d524fbb61e7bb9fb63d8a166db0f3"
4247                            ))),
4248                            RlpNode::word_rlp(&B256::from(hex!(
4249                                "7f3698297308664fbc1b9e2c41d097fbd57d8f364c394f6ad7c71b10291fbf42"
4250                            ))),
4251                            RlpNode::word_rlp(&B256::from(hex!(
4252                                "4a2bc7e19cec63cb5ef5754add0208959b50bcc79f13a22a370f77b277dbe6db"
4253                            ))),
4254                            RlpNode::word_rlp(&B256::from(hex!(
4255                                "40764b8c48de59258e62a3371909a107e76e1b5e847cfa94dbc857e9fd205103"
4256                            ))),
4257                            RlpNode::word_rlp(&B256::from(hex!(
4258                                "2985dca29a7616920d95c43ab62eb013a40e6a0c88c284471e4c3bd22f3b9b25"
4259                            ))),
4260                            RlpNode::word_rlp(&B256::from(hex!(
4261                                "1b6511f7a385e79477239f7dd4a49f52082ecac05aa5bd0de18b1d55fe69d10c"
4262                            ))),
4263                        ],
4264                        TrieMask::new(0b1111111111111111),
4265                    ))
4266                },
4267                masks: TrieMasks {
4268                    hash_mask: Some(TrieMask::new(0b1111111111111111)),
4269                    tree_mask: Some(TrieMask::new(0b0011110100100101)),
4270                },
4271            },
4272            // Branch at 0x4f88072
4273            RevealedSparseNode {
4274                path: removed_branch_path,
4275                node: {
4276                    let stack = vec![
4277                        RlpNode::word_rlp(&B256::from(hex!(
4278                            "15fd4993a41feff1af3b629b32572ab05acddd97c681d82ec2eb89c8a8e3ab9e"
4279                        ))),
4280                        RlpNode::word_rlp(&B256::from(hex!(
4281                            "a272b0b94ced4e6ec7adb41719850cf4a167ad8711d0dda6a810d129258a0d94"
4282                        ))),
4283                    ];
4284                    let branch_node = BranchNode::new(stack, TrieMask::new(0b0001000000000100));
4285                    TrieNode::Branch(branch_node)
4286                },
4287                masks: TrieMasks {
4288                    hash_mask: Some(TrieMask::new(0b0000000000000000)),
4289                    tree_mask: Some(TrieMask::new(0b0000000000000100)),
4290                },
4291            },
4292            // Extension at 0x4f880722
4293            RevealedSparseNode {
4294                path: Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0x2]),
4295                node: {
4296                    let extension_node = ExtensionNode::new(
4297                        Nibbles::from_nibbles([0x6]),
4298                        RlpNode::word_rlp(&B256::from(hex!(
4299                            "56fab2b106a97eae9c7197f86d03bca292da6e0ac725b783082f7d950cc4e0fc"
4300                        ))),
4301                    );
4302                    TrieNode::Extension(extension_node)
4303                },
4304                masks: TrieMasks { hash_mask: None, tree_mask: None },
4305            },
4306            // Leaf at 0x4f88072c
4307            RevealedSparseNode {
4308                path: Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0xc]),
4309                node: {
4310                    let leaf_node = LeafNode::new(
4311                        Nibbles::from_nibbles([
4312                            0x0, 0x7, 0x7, 0xf, 0x8, 0x6, 0x6, 0x1, 0x3, 0x0, 0x8, 0x8, 0xd, 0xf,
4313                            0xc, 0xa, 0xe, 0x6, 0x4, 0x8, 0xa, 0xb, 0xe, 0x8, 0x3, 0x1, 0xf, 0xa,
4314                            0xd, 0xc, 0xa, 0x5, 0x5, 0xa, 0xd, 0x4, 0x3, 0xa, 0xb, 0x1, 0x6, 0x5,
4315                            0xd, 0x1, 0x6, 0x8, 0x0, 0xd, 0xd, 0x5, 0x6, 0x7, 0xb, 0x5, 0xd, 0x6,
4316                        ]),
4317                        hex::decode("8468d3971d").unwrap(),
4318                    );
4319                    TrieNode::Leaf(leaf_node)
4320                },
4321                masks: TrieMasks { hash_mask: None, tree_mask: None },
4322            },
4323        ];
4324
4325        // Create a fresh ParallelSparseTrie
4326        let mut trie = ParallelSparseTrie::from_root(
4327            TrieNode::Extension(ExtensionNode::new(
4328                Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7]),
4329                RlpNode::word_rlp(&B256::from(hex!(
4330                    "56fab2b106a97eae9c7197f86d03bca292da6e0ac725b783082f7d950cc4e0fc"
4331                ))),
4332            )),
4333            TrieMasks::none(),
4334            true,
4335        )
4336        .unwrap();
4337
4338        // Call reveal_nodes
4339        trie.reveal_nodes(nodes).unwrap();
4340
4341        // Remove the leaf at "0x4f88072c077f86613088dfcae648abe831fadca55ad43ab165d1680dd567b5d6"
4342        let leaf_key = Nibbles::from_nibbles([
4343            0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0xc, 0x0, 0x7, 0x7, 0xf, 0x8, 0x6, 0x6, 0x1, 0x3,
4344            0x0, 0x8, 0x8, 0xd, 0xf, 0xc, 0xa, 0xe, 0x6, 0x4, 0x8, 0xa, 0xb, 0xe, 0x8, 0x3, 0x1,
4345            0xf, 0xa, 0xd, 0xc, 0xa, 0x5, 0x5, 0xa, 0xd, 0x4, 0x3, 0xa, 0xb, 0x1, 0x6, 0x5, 0xd,
4346            0x1, 0x6, 0x8, 0x0, 0xd, 0xd, 0x5, 0x6, 0x7, 0xb, 0x5, 0xd, 0x6,
4347        ]);
4348
4349        let mut provider = MockTrieNodeProvider::new();
4350        let revealed_branch = create_branch_node_with_children(&[], []);
4351        let mut encoded = Vec::new();
4352        revealed_branch.encode(&mut encoded);
4353        provider.add_revealed_node(
4354            Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0x2, 0x6]),
4355            RevealedNode {
4356                node: encoded.into(),
4357                tree_mask: None,
4358                // Give it a fake hashmask so that it appears like it will be stored in the db
4359                hash_mask: Some(TrieMask::new(0b1111)),
4360            },
4361        );
4362
4363        trie.remove_leaf(&leaf_key, provider).unwrap();
4364
4365        // Calculate root so that updates are calculated.
4366        trie.root();
4367
4368        // Take updates and assert they are correct
4369        let updates = trie.take_updates();
4370        assert_eq!(
4371            updates.removed_nodes.into_iter().collect::<Vec<_>>(),
4372            vec![removed_branch_path]
4373        );
4374        assert_eq!(updates.updated_nodes.len(), 1);
4375        let updated_node = updates.updated_nodes.get(&branch_path).unwrap();
4376
4377        // Second bit must be set, indicating that the extension's child is in the db
4378        assert_eq!(updated_node.tree_mask, TrieMask::new(0b011110100100101),)
4379    }
4380
4381    #[test]
4382    fn test_parallel_sparse_trie_root() {
4383        // Step 1: Create the trie structure
4384        // Extension node at 0x with key 0x2 (goes to upper subtrie)
4385        let extension_path = Nibbles::new();
4386        let extension_key = Nibbles::from_nibbles([0x2]);
4387
4388        // Branch node at 0x2 with children 0 and 1 (goes to upper subtrie)
4389        let branch_path = Nibbles::from_nibbles([0x2]);
4390
4391        // Leaf nodes at 0x20 and 0x21 (go to lower subtries)
4392        let leaf_1_path = Nibbles::from_nibbles([0x2, 0x0]);
4393        let leaf_1_key = Nibbles::from_nibbles(vec![0; 62]); // Remaining key
4394        let leaf_1_full_path = Nibbles::from_nibbles([vec![0x2, 0x0], vec![0; 62]].concat());
4395
4396        let leaf_2_path = Nibbles::from_nibbles([0x2, 0x1]);
4397        let leaf_2_key = Nibbles::from_nibbles(vec![0; 62]); // Remaining key
4398        let leaf_2_full_path = Nibbles::from_nibbles([vec![0x2, 0x1], vec![0; 62]].concat());
4399
4400        // Create accounts
4401        let account_1 = create_account(1);
4402        let account_2 = create_account(2);
4403
4404        // Create leaf nodes
4405        let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
4406        let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
4407
4408        // Create branch node with children at indices 0 and 1
4409        let branch = create_branch_node_with_children(
4410            &[0, 1],
4411            vec![
4412                RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
4413                RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
4414            ],
4415        );
4416
4417        // Create extension node pointing to branch
4418        let extension = create_extension_node(
4419            extension_key.to_vec(),
4420            RlpNode::from_rlp(&alloy_rlp::encode(&branch)).as_hash().unwrap(),
4421        );
4422
4423        // Step 2: Reveal nodes in the trie
4424        let mut trie = ParallelSparseTrie::from_root(extension, TrieMasks::none(), true).unwrap();
4425        trie.reveal_nodes(vec![
4426            RevealedSparseNode { path: branch_path, node: branch, masks: TrieMasks::none() },
4427            RevealedSparseNode { path: leaf_1_path, node: leaf_1, masks: TrieMasks::none() },
4428            RevealedSparseNode { path: leaf_2_path, node: leaf_2, masks: TrieMasks::none() },
4429        ])
4430        .unwrap();
4431
4432        // Step 3: Reset hashes for all revealed nodes to test actual hash calculation
4433        // Reset upper subtrie node hashes
4434        trie.upper_subtrie.nodes.get_mut(&extension_path).unwrap().set_hash(None);
4435        trie.upper_subtrie.nodes.get_mut(&branch_path).unwrap().set_hash(None);
4436
4437        // Reset lower subtrie node hashes
4438        let leaf_1_subtrie_idx = path_subtrie_index_unchecked(&leaf_1_path);
4439        let leaf_2_subtrie_idx = path_subtrie_index_unchecked(&leaf_2_path);
4440
4441        trie.lower_subtries[leaf_1_subtrie_idx]
4442            .as_revealed_mut()
4443            .unwrap()
4444            .nodes
4445            .get_mut(&leaf_1_path)
4446            .unwrap()
4447            .set_hash(None);
4448        trie.lower_subtries[leaf_2_subtrie_idx]
4449            .as_revealed_mut()
4450            .unwrap()
4451            .nodes
4452            .get_mut(&leaf_2_path)
4453            .unwrap()
4454            .set_hash(None);
4455
4456        // Step 4: Add changed leaf node paths to prefix set
4457        trie.prefix_set.insert(leaf_1_full_path);
4458        trie.prefix_set.insert(leaf_2_full_path);
4459
4460        // Step 5: Calculate root using our implementation
4461        let root = trie.root();
4462
4463        // Step 6: Calculate root using HashBuilder for comparison
4464        let (hash_builder_root, _, _proof_nodes, _, _) = run_hash_builder(
4465            [(leaf_1_full_path, account_1), (leaf_2_full_path, account_2)],
4466            NoopAccountTrieCursor::default(),
4467            Default::default(),
4468            [extension_path, branch_path, leaf_1_full_path, leaf_2_full_path],
4469        );
4470
4471        // Step 7: Verify the roots match
4472        assert_eq!(root, hash_builder_root);
4473
4474        // Verify hashes were computed
4475        let leaf_1_subtrie = trie.lower_subtries[leaf_1_subtrie_idx].as_revealed_ref().unwrap();
4476        let leaf_2_subtrie = trie.lower_subtries[leaf_2_subtrie_idx].as_revealed_ref().unwrap();
4477        assert!(trie.upper_subtrie.nodes.get(&extension_path).unwrap().hash().is_some());
4478        assert!(trie.upper_subtrie.nodes.get(&branch_path).unwrap().hash().is_some());
4479        assert!(leaf_1_subtrie.nodes.get(&leaf_1_path).unwrap().hash().is_some());
4480        assert!(leaf_2_subtrie.nodes.get(&leaf_2_path).unwrap().hash().is_some());
4481    }
4482
4483    #[test]
4484    fn sparse_trie_empty_update_one() {
4485        let ctx = ParallelSparseTrieTestContext;
4486
4487        let key = Nibbles::unpack(B256::with_last_byte(42));
4488        let value = || Account::default();
4489        let value_encoded = || {
4490            let mut account_rlp = Vec::new();
4491            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4492            account_rlp
4493        };
4494
4495        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4496            run_hash_builder(
4497                [(key, value())],
4498                NoopAccountTrieCursor::default(),
4499                Default::default(),
4500                [key],
4501            );
4502
4503        let mut sparse = ParallelSparseTrie::default().with_updates(true);
4504        ctx.update_leaves(&mut sparse, [(key, value_encoded())]);
4505        ctx.assert_with_hash_builder(
4506            &mut sparse,
4507            hash_builder_root,
4508            hash_builder_updates,
4509            hash_builder_proof_nodes,
4510        );
4511    }
4512
4513    #[test]
4514    fn sparse_trie_empty_update_multiple_lower_nibbles() {
4515        let ctx = ParallelSparseTrieTestContext;
4516
4517        let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::<Vec<_>>();
4518        let value = || Account::default();
4519        let value_encoded = || {
4520            let mut account_rlp = Vec::new();
4521            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4522            account_rlp
4523        };
4524
4525        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4526            run_hash_builder(
4527                paths.iter().copied().zip(std::iter::repeat_with(value)),
4528                NoopAccountTrieCursor::default(),
4529                Default::default(),
4530                paths.clone(),
4531            );
4532
4533        let mut sparse = ParallelSparseTrie::default().with_updates(true);
4534        ctx.update_leaves(
4535            &mut sparse,
4536            paths.into_iter().zip(std::iter::repeat_with(value_encoded)),
4537        );
4538
4539        ctx.assert_with_hash_builder(
4540            &mut sparse,
4541            hash_builder_root,
4542            hash_builder_updates,
4543            hash_builder_proof_nodes,
4544        );
4545    }
4546
4547    #[test]
4548    fn sparse_trie_empty_update_multiple_upper_nibbles() {
4549        let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
4550        let value = || Account::default();
4551        let value_encoded = || {
4552            let mut account_rlp = Vec::new();
4553            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4554            account_rlp
4555        };
4556
4557        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4558            run_hash_builder(
4559                paths.iter().copied().zip(std::iter::repeat_with(value)),
4560                NoopAccountTrieCursor::default(),
4561                Default::default(),
4562                paths.clone(),
4563            );
4564
4565        let provider = DefaultTrieNodeProvider;
4566        let mut sparse = ParallelSparseTrie::default().with_updates(true);
4567        for path in &paths {
4568            sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
4569        }
4570        let sparse_root = sparse.root();
4571        let sparse_updates = sparse.take_updates();
4572
4573        assert_eq!(sparse_root, hash_builder_root);
4574        assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
4575        assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
4576    }
4577
4578    #[test]
4579    fn sparse_trie_empty_update_multiple() {
4580        let ctx = ParallelSparseTrieTestContext;
4581
4582        let paths = (0..=255)
4583            .map(|b| {
4584                Nibbles::unpack(if b % 2 == 0 {
4585                    B256::repeat_byte(b)
4586                } else {
4587                    B256::with_last_byte(b)
4588                })
4589            })
4590            .collect::<Vec<_>>();
4591        let value = || Account::default();
4592        let value_encoded = || {
4593            let mut account_rlp = Vec::new();
4594            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4595            account_rlp
4596        };
4597
4598        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4599            run_hash_builder(
4600                paths.iter().sorted_unstable().copied().zip(std::iter::repeat_with(value)),
4601                NoopAccountTrieCursor::default(),
4602                Default::default(),
4603                paths.clone(),
4604            );
4605
4606        let mut sparse = ParallelSparseTrie::default().with_updates(true);
4607        ctx.update_leaves(
4608            &mut sparse,
4609            paths.iter().copied().zip(std::iter::repeat_with(value_encoded)),
4610        );
4611        ctx.assert_with_hash_builder(
4612            &mut sparse,
4613            hash_builder_root,
4614            hash_builder_updates,
4615            hash_builder_proof_nodes,
4616        );
4617    }
4618
4619    #[test]
4620    fn sparse_trie_empty_update_repeated() {
4621        let ctx = ParallelSparseTrieTestContext;
4622
4623        let paths = (0..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
4624        let old_value = Account { nonce: 1, ..Default::default() };
4625        let old_value_encoded = {
4626            let mut account_rlp = Vec::new();
4627            old_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4628            account_rlp
4629        };
4630        let new_value = Account { nonce: 2, ..Default::default() };
4631        let new_value_encoded = {
4632            let mut account_rlp = Vec::new();
4633            new_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
4634            account_rlp
4635        };
4636
4637        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4638            run_hash_builder(
4639                paths.iter().copied().zip(std::iter::repeat_with(|| old_value)),
4640                NoopAccountTrieCursor::default(),
4641                Default::default(),
4642                paths.clone(),
4643            );
4644
4645        let mut sparse = ParallelSparseTrie::default().with_updates(true);
4646        ctx.update_leaves(
4647            &mut sparse,
4648            paths.iter().copied().zip(std::iter::repeat(old_value_encoded)),
4649        );
4650        ctx.assert_with_hash_builder(
4651            &mut sparse,
4652            hash_builder_root,
4653            hash_builder_updates,
4654            hash_builder_proof_nodes,
4655        );
4656
4657        let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
4658            run_hash_builder(
4659                paths.iter().copied().zip(std::iter::repeat(new_value)),
4660                NoopAccountTrieCursor::default(),
4661                Default::default(),
4662                paths.clone(),
4663            );
4664
4665        ctx.update_leaves(
4666            &mut sparse,
4667            paths.iter().copied().zip(std::iter::repeat(new_value_encoded)),
4668        );
4669        ctx.assert_with_hash_builder(
4670            &mut sparse,
4671            hash_builder_root,
4672            hash_builder_updates,
4673            hash_builder_proof_nodes,
4674        );
4675    }
4676
4677    #[test]
4678    fn sparse_trie_remove_leaf() {
4679        let ctx = ParallelSparseTrieTestContext;
4680        let provider = DefaultTrieNodeProvider;
4681        let mut sparse = ParallelSparseTrie::default();
4682
4683        let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
4684
4685        ctx.update_leaves(
4686            &mut sparse,
4687            [
4688                (Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone()),
4689                (Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone()),
4690                (Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone()),
4691                (Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone()),
4692                (Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone()),
4693                (Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value),
4694            ],
4695        );
4696
4697        // Extension (Key = 5)
4698        // └── Branch (Mask = 1011)
4699        //     ├── 0 -> Extension (Key = 23)
4700        //     │        └── Branch (Mask = 0101)
4701        //     │              ├── 1 -> Leaf (Key = 1, Path = 50231)
4702        //     │              └── 3 -> Leaf (Key = 3, Path = 50233)
4703        //     ├── 2 -> Leaf (Key = 013, Path = 52013)
4704        //     └── 3 -> Branch (Mask = 0101)
4705        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
4706        //                └── 3 -> Branch (Mask = 1010)
4707        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
4708        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
4709        pretty_assertions::assert_eq!(
4710            parallel_sparse_trie_nodes(&sparse)
4711                .into_iter()
4712                .map(|(k, v)| (*k, v.clone()))
4713                .collect::<BTreeMap<_, _>>(),
4714            BTreeMap::from_iter([
4715                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4716                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1101.into())),
4717                (
4718                    Nibbles::from_nibbles([0x5, 0x0]),
4719                    SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
4720                ),
4721                (
4722                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
4723                    SparseNode::new_branch(0b1010.into())
4724                ),
4725                (
4726                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
4727                    SparseNode::new_leaf(Nibbles::default())
4728                ),
4729                (
4730                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
4731                    SparseNode::new_leaf(Nibbles::default())
4732                ),
4733                (
4734                    Nibbles::from_nibbles([0x5, 0x2]),
4735                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x1, 0x3]))
4736                ),
4737                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
4738                (
4739                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
4740                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
4741                ),
4742                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
4743                (
4744                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
4745                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
4746                ),
4747                (
4748                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
4749                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
4750                )
4751            ])
4752        );
4753
4754        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), &provider).unwrap();
4755
4756        // Extension (Key = 5)
4757        // └── Branch (Mask = 1001)
4758        //     ├── 0 -> Extension (Key = 23)
4759        //     │        └── Branch (Mask = 0101)
4760        //     │              ├── 1 -> Leaf (Key = 0231, Path = 50231)
4761        //     │              └── 3 -> Leaf (Key = 0233, Path = 50233)
4762        //     └── 3 -> Branch (Mask = 0101)
4763        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
4764        //                └── 3 -> Branch (Mask = 1010)
4765        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
4766        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
4767        pretty_assertions::assert_eq!(
4768            parallel_sparse_trie_nodes(&sparse)
4769                .into_iter()
4770                .map(|(k, v)| (*k, v.clone()))
4771                .collect::<BTreeMap<_, _>>(),
4772            BTreeMap::from_iter([
4773                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4774                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
4775                (
4776                    Nibbles::from_nibbles([0x5, 0x0]),
4777                    SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
4778                ),
4779                (
4780                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
4781                    SparseNode::new_branch(0b1010.into())
4782                ),
4783                (
4784                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
4785                    SparseNode::new_leaf(Nibbles::default())
4786                ),
4787                (
4788                    Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
4789                    SparseNode::new_leaf(Nibbles::default())
4790                ),
4791                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
4792                (
4793                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
4794                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
4795                ),
4796                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
4797                (
4798                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
4799                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
4800                ),
4801                (
4802                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
4803                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
4804                )
4805            ])
4806        );
4807
4808        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), &provider).unwrap();
4809
4810        // Extension (Key = 5)
4811        // └── Branch (Mask = 1001)
4812        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
4813        //     └── 3 -> Branch (Mask = 0101)
4814        //                ├── 1 -> Leaf (Key = 3102, Path = 53102)
4815        //                └── 3 -> Branch (Mask = 1010)
4816        //                       ├── 0 -> Leaf (Key = 3302, Path = 53302)
4817        //                       └── 2 -> Leaf (Key = 3320, Path = 53320)
4818        pretty_assertions::assert_eq!(
4819            parallel_sparse_trie_nodes(&sparse)
4820                .into_iter()
4821                .map(|(k, v)| (*k, v.clone()))
4822                .collect::<BTreeMap<_, _>>(),
4823            BTreeMap::from_iter([
4824                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4825                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
4826                (
4827                    Nibbles::from_nibbles([0x5, 0x0]),
4828                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
4829                ),
4830                (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
4831                (
4832                    Nibbles::from_nibbles([0x5, 0x3, 0x1]),
4833                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
4834                ),
4835                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
4836                (
4837                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
4838                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
4839                ),
4840                (
4841                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
4842                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
4843                )
4844            ])
4845        );
4846
4847        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), &provider).unwrap();
4848
4849        // Extension (Key = 5)
4850        // └── Branch (Mask = 1001)
4851        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
4852        //     └── 3 -> Branch (Mask = 1010)
4853        //                ├── 0 -> Leaf (Key = 3302, Path = 53302)
4854        //                └── 2 -> Leaf (Key = 3320, Path = 53320)
4855        pretty_assertions::assert_eq!(
4856            parallel_sparse_trie_nodes(&sparse)
4857                .into_iter()
4858                .map(|(k, v)| (*k, v.clone()))
4859                .collect::<BTreeMap<_, _>>(),
4860            BTreeMap::from_iter([
4861                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4862                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
4863                (
4864                    Nibbles::from_nibbles([0x5, 0x0]),
4865                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
4866                ),
4867                (
4868                    Nibbles::from_nibbles([0x5, 0x3]),
4869                    SparseNode::new_ext(Nibbles::from_nibbles([0x3]))
4870                ),
4871                (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
4872                (
4873                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
4874                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
4875                ),
4876                (
4877                    Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
4878                    SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
4879                )
4880            ])
4881        );
4882
4883        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &provider).unwrap();
4884
4885        // Extension (Key = 5)
4886        // └── Branch (Mask = 1001)
4887        //     ├── 0 -> Leaf (Key = 0233, Path = 50233)
4888        //     └── 3 -> Leaf (Key = 3302, Path = 53302)
4889        pretty_assertions::assert_eq!(
4890            parallel_sparse_trie_nodes(&sparse)
4891                .into_iter()
4892                .map(|(k, v)| (*k, v.clone()))
4893                .collect::<BTreeMap<_, _>>(),
4894            BTreeMap::from_iter([
4895                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4896                (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
4897                (
4898                    Nibbles::from_nibbles([0x5, 0x0]),
4899                    SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
4900                ),
4901                (
4902                    Nibbles::from_nibbles([0x5, 0x3]),
4903                    SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x0, 0x2]))
4904                ),
4905            ])
4906        );
4907
4908        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), &provider).unwrap();
4909
4910        // Leaf (Key = 53302)
4911        pretty_assertions::assert_eq!(
4912            parallel_sparse_trie_nodes(&sparse)
4913                .into_iter()
4914                .map(|(k, v)| (*k, v.clone()))
4915                .collect::<BTreeMap<_, _>>(),
4916            BTreeMap::from_iter([(
4917                Nibbles::default(),
4918                SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]))
4919            ),])
4920        );
4921
4922        sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &provider).unwrap();
4923
4924        // Empty
4925        pretty_assertions::assert_eq!(
4926            parallel_sparse_trie_nodes(&sparse)
4927                .into_iter()
4928                .map(|(k, v)| (*k, v.clone()))
4929                .collect::<BTreeMap<_, _>>(),
4930            BTreeMap::from_iter([(Nibbles::default(), SparseNode::Empty)])
4931        );
4932    }
4933
4934    #[test]
4935    fn sparse_trie_remove_leaf_blinded() {
4936        let leaf = LeafNode::new(
4937            Nibbles::default(),
4938            alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
4939        );
4940        let branch = TrieNode::Branch(BranchNode::new(
4941            vec![
4942                RlpNode::word_rlp(&B256::repeat_byte(1)),
4943                RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
4944            ],
4945            TrieMask::new(0b11),
4946        ));
4947
4948        let provider = DefaultTrieNodeProvider;
4949        let mut sparse = ParallelSparseTrie::from_root(
4950            branch.clone(),
4951            TrieMasks { hash_mask: Some(TrieMask::new(0b01)), tree_mask: None },
4952            false,
4953        )
4954        .unwrap();
4955
4956        // Reveal a branch node and one of its children
4957        //
4958        // Branch (Mask = 11)
4959        // ├── 0 -> Hash (Path = 0)
4960        // └── 1 -> Leaf (Path = 1)
4961        sparse
4962            .reveal_nodes(vec![
4963                RevealedSparseNode {
4964                    path: Nibbles::default(),
4965                    node: branch,
4966                    masks: TrieMasks { hash_mask: None, tree_mask: Some(TrieMask::new(0b01)) },
4967                },
4968                RevealedSparseNode {
4969                    path: Nibbles::from_nibbles([0x1]),
4970                    node: TrieNode::Leaf(leaf),
4971                    masks: TrieMasks::none(),
4972                },
4973            ])
4974            .unwrap();
4975
4976        // Removing a blinded leaf should result in an error
4977        assert_matches!(
4978            sparse.remove_leaf(&Nibbles::from_nibbles([0x0]), &provider).map_err(|e| e.into_kind()),
4979            Err(SparseTrieErrorKind::BlindedNode { path, hash }) if path == Nibbles::from_nibbles([0x0]) && hash == B256::repeat_byte(1)
4980        );
4981    }
4982
4983    #[test]
4984    fn sparse_trie_remove_leaf_non_existent() {
4985        let leaf = LeafNode::new(
4986            Nibbles::default(),
4987            alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
4988        );
4989        let branch = TrieNode::Branch(BranchNode::new(
4990            vec![
4991                RlpNode::word_rlp(&B256::repeat_byte(1)),
4992                RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
4993            ],
4994            TrieMask::new(0b11),
4995        ));
4996
4997        let provider = DefaultTrieNodeProvider;
4998        let mut sparse = ParallelSparseTrie::from_root(
4999            branch.clone(),
5000            TrieMasks { hash_mask: Some(TrieMask::new(0b01)), tree_mask: None },
5001            false,
5002        )
5003        .unwrap();
5004
5005        // Reveal a branch node and one of its children
5006        //
5007        // Branch (Mask = 11)
5008        // ├── 0 -> Hash (Path = 0)
5009        // └── 1 -> Leaf (Path = 1)
5010        sparse
5011            .reveal_nodes(vec![
5012                RevealedSparseNode {
5013                    path: Nibbles::default(),
5014                    node: branch,
5015                    masks: TrieMasks { hash_mask: None, tree_mask: Some(TrieMask::new(0b01)) },
5016                },
5017                RevealedSparseNode {
5018                    path: Nibbles::from_nibbles([0x1]),
5019                    node: TrieNode::Leaf(leaf),
5020                    masks: TrieMasks::none(),
5021                },
5022            ])
5023            .unwrap();
5024
5025        // Removing a non-existent leaf should be a noop
5026        let sparse_old = sparse.clone();
5027        assert_matches!(sparse.remove_leaf(&Nibbles::from_nibbles([0x2]), &provider), Ok(()));
5028        assert_eq!(sparse, sparse_old);
5029    }
5030
5031    #[test]
5032    fn sparse_trie_fuzz() {
5033        // Having only the first 3 nibbles set, we narrow down the range of keys
5034        // to 4096 different hashes. It allows us to generate collisions more likely
5035        // to test the sparse trie updates.
5036        const KEY_NIBBLES_LEN: usize = 3;
5037
5038        fn test(updates: Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)>) {
5039            {
5040                let mut state = BTreeMap::default();
5041                let default_provider = DefaultTrieNodeProvider;
5042                let provider_factory = create_test_provider_factory();
5043                let mut sparse = ParallelSparseTrie::default().with_updates(true);
5044
5045                for (update, keys_to_delete) in updates {
5046                    // Insert state updates into the sparse trie and calculate the root
5047                    for (key, account) in update.clone() {
5048                        let account = account.into_trie_account(EMPTY_ROOT_HASH);
5049                        let mut account_rlp = Vec::new();
5050                        account.encode(&mut account_rlp);
5051                        sparse.update_leaf(key, account_rlp, &default_provider).unwrap();
5052                    }
5053                    // We need to clone the sparse trie, so that all updated branch nodes are
5054                    // preserved, and not only those that were changed after the last call to
5055                    // `root()`.
5056                    let mut updated_sparse = sparse.clone();
5057                    let sparse_root = updated_sparse.root();
5058                    let sparse_updates = updated_sparse.take_updates();
5059
5060                    // Insert state updates into the hash builder and calculate the root
5061                    state.extend(update);
5062                    let provider = provider_factory.provider().unwrap();
5063                    let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
5064                    let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5065                        run_hash_builder(
5066                            state.clone(),
5067                            trie_cursor.account_trie_cursor().unwrap(),
5068                            Default::default(),
5069                            state.keys().copied(),
5070                        );
5071
5072                    // Extract account nodes before moving hash_builder_updates
5073                    let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
5074
5075                    // Write trie updates to the database
5076                    let provider_rw = provider_factory.provider_rw().unwrap();
5077                    provider_rw.write_trie_updates(hash_builder_updates).unwrap();
5078                    provider_rw.commit().unwrap();
5079
5080                    // Assert that the sparse trie root matches the hash builder root
5081                    assert_eq!(sparse_root, hash_builder_root);
5082                    // Assert that the sparse trie updates match the hash builder updates
5083                    pretty_assertions::assert_eq!(
5084                        BTreeMap::from_iter(sparse_updates.updated_nodes),
5085                        BTreeMap::from_iter(hash_builder_account_nodes)
5086                    );
5087                    // Assert that the sparse trie nodes match the hash builder proof nodes
5088                    assert_eq_parallel_sparse_trie_proof_nodes(
5089                        &updated_sparse,
5090                        hash_builder_proof_nodes,
5091                    );
5092
5093                    // Delete some keys from both the hash builder and the sparse trie and check
5094                    // that the sparse trie root still matches the hash builder root
5095                    for key in &keys_to_delete {
5096                        state.remove(key).unwrap();
5097                        sparse.remove_leaf(key, &default_provider).unwrap();
5098                    }
5099
5100                    // We need to clone the sparse trie, so that all updated branch nodes are
5101                    // preserved, and not only those that were changed after the last call to
5102                    // `root()`.
5103                    let mut updated_sparse = sparse.clone();
5104                    let sparse_root = updated_sparse.root();
5105                    let sparse_updates = updated_sparse.take_updates();
5106
5107                    let provider = provider_factory.provider().unwrap();
5108                    let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
5109                    let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5110                        run_hash_builder(
5111                            state.clone(),
5112                            trie_cursor.account_trie_cursor().unwrap(),
5113                            keys_to_delete
5114                                .iter()
5115                                .map(|nibbles| B256::from_slice(&nibbles.pack()))
5116                                .collect(),
5117                            state.keys().copied(),
5118                        );
5119
5120                    // Extract account nodes before moving hash_builder_updates
5121                    let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
5122
5123                    // Write trie updates to the database
5124                    let provider_rw = provider_factory.provider_rw().unwrap();
5125                    provider_rw.write_trie_updates(hash_builder_updates).unwrap();
5126                    provider_rw.commit().unwrap();
5127
5128                    // Assert that the sparse trie root matches the hash builder root
5129                    assert_eq!(sparse_root, hash_builder_root);
5130                    // Assert that the sparse trie updates match the hash builder updates
5131                    pretty_assertions::assert_eq!(
5132                        BTreeMap::from_iter(sparse_updates.updated_nodes),
5133                        BTreeMap::from_iter(hash_builder_account_nodes)
5134                    );
5135                    // Assert that the sparse trie nodes match the hash builder proof nodes
5136                    assert_eq_parallel_sparse_trie_proof_nodes(
5137                        &updated_sparse,
5138                        hash_builder_proof_nodes,
5139                    );
5140                }
5141            }
5142        }
5143
5144        fn transform_updates(
5145            updates: Vec<BTreeMap<Nibbles, Account>>,
5146            mut rng: impl rand::Rng,
5147        ) -> Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)> {
5148            let mut keys = BTreeSet::new();
5149            updates
5150                .into_iter()
5151                .map(|update| {
5152                    keys.extend(update.keys().copied());
5153
5154                    let keys_to_delete_len = update.len() / 2;
5155                    let keys_to_delete = (0..keys_to_delete_len)
5156                        .map(|_| {
5157                            let key =
5158                                *rand::seq::IteratorRandom::choose(keys.iter(), &mut rng).unwrap();
5159                            keys.take(&key).unwrap()
5160                        })
5161                        .collect();
5162
5163                    (update, keys_to_delete)
5164                })
5165                .collect::<Vec<_>>()
5166        }
5167
5168        proptest!(ProptestConfig::with_cases(10), |(
5169            updates in proptest::collection::vec(
5170                proptest::collection::btree_map(
5171                    any_with::<Nibbles>(SizeRange::new(KEY_NIBBLES_LEN..=KEY_NIBBLES_LEN)).prop_map(pad_nibbles_right),
5172                    arb::<Account>(),
5173                    1..50,
5174                ),
5175                1..50,
5176            ).prop_perturb(transform_updates)
5177        )| {
5178            test(updates)
5179        });
5180    }
5181
5182    #[test]
5183    fn sparse_trie_fuzz_vs_serial() {
5184        // Having only the first 3 nibbles set, we narrow down the range of keys
5185        // to 4096 different hashes. It allows us to generate collisions more likely
5186        // to test the sparse trie updates.
5187        const KEY_NIBBLES_LEN: usize = 3;
5188
5189        fn test(updates: Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)>) {
5190            let default_provider = DefaultTrieNodeProvider;
5191            let mut serial = SerialSparseTrie::default().with_updates(true);
5192            let mut parallel = ParallelSparseTrie::default().with_updates(true);
5193
5194            for (update, keys_to_delete) in updates {
5195                // Perform leaf updates on both tries
5196                for (key, account) in update.clone() {
5197                    let account = account.into_trie_account(EMPTY_ROOT_HASH);
5198                    let mut account_rlp = Vec::new();
5199                    account.encode(&mut account_rlp);
5200                    serial.update_leaf(key, account_rlp.clone(), &default_provider).unwrap();
5201                    parallel.update_leaf(key, account_rlp, &default_provider).unwrap();
5202                }
5203
5204                // Calculate roots and assert their equality
5205                let serial_root = serial.root();
5206                let parallel_root = parallel.root();
5207                assert_eq!(parallel_root, serial_root);
5208
5209                // Assert that both tries produce the same updates
5210                let serial_updates = serial.take_updates();
5211                let parallel_updates = parallel.take_updates();
5212                pretty_assertions::assert_eq!(
5213                    BTreeMap::from_iter(parallel_updates.updated_nodes),
5214                    BTreeMap::from_iter(serial_updates.updated_nodes),
5215                );
5216                pretty_assertions::assert_eq!(
5217                    BTreeSet::from_iter(parallel_updates.removed_nodes),
5218                    BTreeSet::from_iter(serial_updates.removed_nodes),
5219                );
5220
5221                // Perform leaf removals on both tries
5222                for key in &keys_to_delete {
5223                    parallel.remove_leaf(key, &default_provider).unwrap();
5224                    serial.remove_leaf(key, &default_provider).unwrap();
5225                }
5226
5227                // Calculate roots and assert their equality
5228                let serial_root = serial.root();
5229                let parallel_root = parallel.root();
5230                assert_eq!(parallel_root, serial_root);
5231
5232                // Assert that both tries produce the same updates
5233                let serial_updates = serial.take_updates();
5234                let parallel_updates = parallel.take_updates();
5235                pretty_assertions::assert_eq!(
5236                    BTreeMap::from_iter(parallel_updates.updated_nodes),
5237                    BTreeMap::from_iter(serial_updates.updated_nodes),
5238                );
5239                pretty_assertions::assert_eq!(
5240                    BTreeSet::from_iter(parallel_updates.removed_nodes),
5241                    BTreeSet::from_iter(serial_updates.removed_nodes),
5242                );
5243            }
5244        }
5245
5246        fn transform_updates(
5247            updates: Vec<BTreeMap<Nibbles, Account>>,
5248            mut rng: impl rand::Rng,
5249        ) -> Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)> {
5250            let mut keys = BTreeSet::new();
5251            updates
5252                .into_iter()
5253                .map(|update| {
5254                    keys.extend(update.keys().copied());
5255
5256                    let keys_to_delete_len = update.len() / 2;
5257                    let keys_to_delete = (0..keys_to_delete_len)
5258                        .map(|_| {
5259                            let key =
5260                                *rand::seq::IteratorRandom::choose(keys.iter(), &mut rng).unwrap();
5261                            keys.take(&key).unwrap()
5262                        })
5263                        .collect();
5264
5265                    (update, keys_to_delete)
5266                })
5267                .collect::<Vec<_>>()
5268        }
5269
5270        proptest!(ProptestConfig::with_cases(10), |(
5271            updates in proptest::collection::vec(
5272                proptest::collection::btree_map(
5273                    any_with::<Nibbles>(SizeRange::new(KEY_NIBBLES_LEN..=KEY_NIBBLES_LEN)).prop_map(pad_nibbles_right),
5274                    arb::<Account>(),
5275                    1..50,
5276                ),
5277                1..50,
5278            ).prop_perturb(transform_updates)
5279        )| {
5280            test(updates)
5281        });
5282    }
5283
5284    #[test]
5285    fn sparse_trie_two_leaves_at_lower_roots() {
5286        let provider = DefaultTrieNodeProvider;
5287        let mut trie = ParallelSparseTrie::default().with_updates(true);
5288        let key_50 = Nibbles::unpack(hex!(
5289            "0x5000000000000000000000000000000000000000000000000000000000000000"
5290        ));
5291        let key_51 = Nibbles::unpack(hex!(
5292            "0x5100000000000000000000000000000000000000000000000000000000000000"
5293        ));
5294
5295        let account = Account::default().into_trie_account(EMPTY_ROOT_HASH);
5296        let mut account_rlp = Vec::new();
5297        account.encode(&mut account_rlp);
5298
5299        // Add a leaf and calculate the root.
5300        trie.update_leaf(key_50, account_rlp.clone(), &provider).unwrap();
5301        trie.root();
5302
5303        // Add a second leaf and assert that the root is the expected value.
5304        trie.update_leaf(key_51, account_rlp.clone(), &provider).unwrap();
5305
5306        let expected_root =
5307            hex!("0xdaf0ef9f91a2f179bb74501209effdb5301db1697bcab041eca2234b126e25de");
5308        let root = trie.root();
5309        assert_eq!(root, expected_root);
5310        assert_eq!(SparseTrieUpdates::default(), trie.take_updates());
5311    }
5312
5313    /// We have three leaves that share the same prefix: 0x00, 0x01 and 0x02. Hash builder trie has
5314    /// only nodes 0x00 and 0x01, and we have proofs for them. Node B is new and inserted in the
5315    /// sparse trie first.
5316    ///
5317    /// 1. Reveal the hash builder proof to leaf 0x00 in the sparse trie.
5318    /// 2. Insert leaf 0x01 into the sparse trie.
5319    /// 3. Reveal the hash builder proof to leaf 0x02 in the sparse trie.
5320    ///
5321    /// The hash builder proof to the leaf 0x02 didn't have the leaf 0x01 at the corresponding
5322    /// nibble of the branch node, so we need to adjust the branch node instead of fully
5323    /// replacing it.
5324    #[test]
5325    fn sparse_trie_reveal_node_1() {
5326        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00]));
5327        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01]));
5328        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x02]));
5329        let value = || Account::default();
5330        let value_encoded = || {
5331            let mut account_rlp = Vec::new();
5332            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5333            account_rlp
5334        };
5335
5336        // Generate the proof for the root node and initialize the sparse trie with it
5337        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5338            run_hash_builder(
5339                [(key1(), value()), (key3(), value())],
5340                NoopAccountTrieCursor::default(),
5341                Default::default(),
5342                [Nibbles::default()],
5343            );
5344
5345        let provider = DefaultTrieNodeProvider;
5346        let mut sparse = ParallelSparseTrie::from_root(
5347            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
5348            TrieMasks {
5349                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
5350                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
5351            },
5352            false,
5353        )
5354        .unwrap();
5355
5356        // Generate the proof for the first key and reveal it in the sparse trie
5357        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5358            run_hash_builder(
5359                [(key1(), value()), (key3(), value())],
5360                NoopAccountTrieCursor::default(),
5361                Default::default(),
5362                [key1()],
5363            );
5364        let revealed_nodes: Vec<RevealedSparseNode> = hash_builder_proof_nodes
5365            .nodes_sorted()
5366            .into_iter()
5367            .map(|(path, node)| {
5368                let hash_mask = branch_node_hash_masks.get(&path).copied();
5369                let tree_mask = branch_node_tree_masks.get(&path).copied();
5370                RevealedSparseNode {
5371                    path,
5372                    node: TrieNode::decode(&mut &node[..]).unwrap(),
5373                    masks: TrieMasks { hash_mask, tree_mask },
5374                }
5375            })
5376            .collect();
5377        sparse.reveal_nodes(revealed_nodes).unwrap();
5378
5379        // Check that the branch node exists with only two nibbles set
5380        assert_eq!(
5381            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5382            Some(&SparseNode::new_branch(0b101.into()))
5383        );
5384
5385        // Insert the leaf for the second key
5386        sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
5387
5388        // Check that the branch node was updated and another nibble was set
5389        assert_eq!(
5390            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5391            Some(&SparseNode::new_branch(0b111.into()))
5392        );
5393
5394        // Generate the proof for the third key and reveal it in the sparse trie
5395        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5396            run_hash_builder(
5397                [(key1(), value()), (key3(), value())],
5398                NoopAccountTrieCursor::default(),
5399                Default::default(),
5400                [key3()],
5401            );
5402        let revealed_nodes: Vec<RevealedSparseNode> = hash_builder_proof_nodes
5403            .nodes_sorted()
5404            .into_iter()
5405            .map(|(path, node)| {
5406                let hash_mask = branch_node_hash_masks.get(&path).copied();
5407                let tree_mask = branch_node_tree_masks.get(&path).copied();
5408                RevealedSparseNode {
5409                    path,
5410                    node: TrieNode::decode(&mut &node[..]).unwrap(),
5411                    masks: TrieMasks { hash_mask, tree_mask },
5412                }
5413            })
5414            .collect();
5415        sparse.reveal_nodes(revealed_nodes).unwrap();
5416
5417        // Check that nothing changed in the branch node
5418        assert_eq!(
5419            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5420            Some(&SparseNode::new_branch(0b111.into()))
5421        );
5422
5423        // Generate the nodes for the full trie with all three key using the hash builder, and
5424        // compare them to the sparse trie
5425        let (_, _, hash_builder_proof_nodes, _, _) = run_hash_builder(
5426            [(key1(), value()), (key2(), value()), (key3(), value())],
5427            NoopAccountTrieCursor::default(),
5428            Default::default(),
5429            [key1(), key2(), key3()],
5430        );
5431
5432        assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
5433    }
5434
5435    /// We have three leaves: 0x0000, 0x0101, and 0x0102. Hash builder trie has all nodes, and we
5436    /// have proofs for them.
5437    ///
5438    /// 1. Reveal the hash builder proof to leaf 0x00 in the sparse trie.
5439    /// 2. Remove leaf 0x00 from the sparse trie (that will remove the branch node and create an
5440    ///    extension node with the key 0x0000).
5441    /// 3. Reveal the hash builder proof to leaf 0x0101 in the sparse trie.
5442    ///
5443    /// The hash builder proof to the leaf 0x0101 had a branch node in the path, but we turned it
5444    /// into an extension node, so it should ignore this node.
5445    #[test]
5446    fn sparse_trie_reveal_node_2() {
5447        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x00]));
5448        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x01]));
5449        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x02]));
5450        let value = || Account::default();
5451
5452        // Generate the proof for the root node and initialize the sparse trie with it
5453        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5454            run_hash_builder(
5455                [(key1(), value()), (key2(), value()), (key3(), value())],
5456                NoopAccountTrieCursor::default(),
5457                Default::default(),
5458                [Nibbles::default()],
5459            );
5460
5461        let provider = DefaultTrieNodeProvider;
5462        let mut sparse = ParallelSparseTrie::from_root(
5463            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
5464            TrieMasks {
5465                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
5466                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
5467            },
5468            false,
5469        )
5470        .unwrap();
5471
5472        // Generate the proof for the children of the root branch node and reveal it in the sparse
5473        // trie
5474        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5475            run_hash_builder(
5476                [(key1(), value()), (key2(), value()), (key3(), value())],
5477                NoopAccountTrieCursor::default(),
5478                Default::default(),
5479                [key1(), Nibbles::from_nibbles_unchecked([0x01])],
5480            );
5481        let revealed_nodes: Vec<RevealedSparseNode> = hash_builder_proof_nodes
5482            .nodes_sorted()
5483            .into_iter()
5484            .map(|(path, node)| {
5485                let hash_mask = branch_node_hash_masks.get(&path).copied();
5486                let tree_mask = branch_node_tree_masks.get(&path).copied();
5487                RevealedSparseNode {
5488                    path,
5489                    node: TrieNode::decode(&mut &node[..]).unwrap(),
5490                    masks: TrieMasks { hash_mask, tree_mask },
5491                }
5492            })
5493            .collect();
5494        sparse.reveal_nodes(revealed_nodes).unwrap();
5495
5496        // Check that the branch node exists
5497        assert_eq!(
5498            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5499            Some(&SparseNode::new_branch(0b11.into()))
5500        );
5501
5502        // Remove the leaf for the first key
5503        sparse.remove_leaf(&key1(), &provider).unwrap();
5504
5505        // Check that the branch node was turned into an extension node
5506        assert_eq!(
5507            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5508            Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
5509        );
5510
5511        // Generate the proof for the third key and reveal it in the sparse trie
5512        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5513            run_hash_builder(
5514                [(key1(), value()), (key2(), value()), (key3(), value())],
5515                NoopAccountTrieCursor::default(),
5516                Default::default(),
5517                [key2()],
5518            );
5519        let revealed_nodes: Vec<RevealedSparseNode> = hash_builder_proof_nodes
5520            .nodes_sorted()
5521            .into_iter()
5522            .map(|(path, node)| {
5523                let hash_mask = branch_node_hash_masks.get(&path).copied();
5524                let tree_mask = branch_node_tree_masks.get(&path).copied();
5525                RevealedSparseNode {
5526                    path,
5527                    node: TrieNode::decode(&mut &node[..]).unwrap(),
5528                    masks: TrieMasks { hash_mask, tree_mask },
5529                }
5530            })
5531            .collect();
5532        sparse.reveal_nodes(revealed_nodes).unwrap();
5533
5534        // Check that nothing changed in the extension node
5535        assert_eq!(
5536            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5537            Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
5538        );
5539    }
5540
5541    /// We have two leaves that share the same prefix: 0x0001 and 0x0002, and a leaf with a
5542    /// different prefix: 0x0100. Hash builder trie has only the first two leaves, and we have
5543    /// proofs for them.
5544    ///
5545    /// 1. Insert the leaf 0x0100 into the sparse trie, and check that the root extension node was
5546    ///    turned into a branch node.
5547    /// 2. Reveal the leaf 0x0001 in the sparse trie, and check that the root branch node wasn't
5548    ///    overwritten with the extension node from the proof.
5549    #[test]
5550    fn sparse_trie_reveal_node_3() {
5551        let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x01]));
5552        let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x02]));
5553        let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x00]));
5554        let value = || Account::default();
5555        let value_encoded = || {
5556            let mut account_rlp = Vec::new();
5557            value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5558            account_rlp
5559        };
5560
5561        // Generate the proof for the root node and initialize the sparse trie with it
5562        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5563            run_hash_builder(
5564                [(key1(), value()), (key2(), value())],
5565                NoopAccountTrieCursor::default(),
5566                Default::default(),
5567                [Nibbles::default()],
5568            );
5569
5570        let provider = DefaultTrieNodeProvider;
5571        let mut sparse = ParallelSparseTrie::from_root(
5572            TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
5573            TrieMasks {
5574                hash_mask: branch_node_hash_masks.get(&Nibbles::default()).copied(),
5575                tree_mask: branch_node_tree_masks.get(&Nibbles::default()).copied(),
5576            },
5577            false,
5578        )
5579        .unwrap();
5580
5581        // Check that the root extension node exists
5582        assert_matches!(
5583            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5584            Some(SparseNode::Extension { key, hash: None, store_in_db_trie: None }) if *key == Nibbles::from_nibbles([0x00])
5585        );
5586
5587        // Insert the leaf with a different prefix
5588        sparse.update_leaf(key3(), value_encoded(), &provider).unwrap();
5589
5590        // Check that the extension node was turned into a branch node
5591        assert_matches!(
5592            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5593            Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
5594        );
5595
5596        // Generate the proof for the first key and reveal it in the sparse trie
5597        let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5598            run_hash_builder(
5599                [(key1(), value()), (key2(), value())],
5600                NoopAccountTrieCursor::default(),
5601                Default::default(),
5602                [key1()],
5603            );
5604        let revealed_nodes: Vec<RevealedSparseNode> = hash_builder_proof_nodes
5605            .nodes_sorted()
5606            .into_iter()
5607            .map(|(path, node)| {
5608                let hash_mask = branch_node_hash_masks.get(&path).copied();
5609                let tree_mask = branch_node_tree_masks.get(&path).copied();
5610                RevealedSparseNode {
5611                    path,
5612                    node: TrieNode::decode(&mut &node[..]).unwrap(),
5613                    masks: TrieMasks { hash_mask, tree_mask },
5614                }
5615            })
5616            .collect();
5617        sparse.reveal_nodes(revealed_nodes).unwrap();
5618
5619        // Check that the branch node wasn't overwritten by the extension node in the proof
5620        assert_matches!(
5621            sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5622            Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
5623        );
5624    }
5625
5626    #[test]
5627    fn test_update_leaf_cross_level() {
5628        let ctx = ParallelSparseTrieTestContext;
5629        let mut trie =
5630            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5631
5632        // Test adding leaves that demonstrate the cross-level behavior
5633        // Based on the example: leaves 0x1234, 0x1245, 0x1334, 0x1345
5634        //
5635        // Final trie structure:
5636        // Upper trie:
5637        //   0x: Extension { key: 0x1 }
5638        //   └── 0x1: Branch { state_mask: 0x1100 }
5639        //       └── Subtrie (0x12): pointer to lower subtrie
5640        //       └── Subtrie (0x13): pointer to lower subtrie
5641        //
5642        // Lower subtrie (0x12):
5643        //   0x12: Branch { state_mask: 0x8 | 0x10 }
5644        //   ├── 0x123: Leaf { key: 0x4 }
5645        //   └── 0x124: Leaf { key: 0x5 }
5646        //
5647        // Lower subtrie (0x13):
5648        //   0x13: Branch { state_mask: 0x8 | 0x10 }
5649        //   ├── 0x133: Leaf { key: 0x4 }
5650        //   └── 0x134: Leaf { key: 0x5 }
5651
5652        // First add leaf 0x1345 - this should create a leaf in upper trie at 0x
5653        let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x3, 0x4, 0x5], 1);
5654        trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
5655
5656        // Verify upper trie has a leaf at the root with key 1345
5657        ctx.assert_upper_subtrie(&trie)
5658            .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x3, 0x4, 0x5]))
5659            .has_value(&leaf1_path, &value1);
5660
5661        // Add leaf 0x1234 - this should go first in the upper subtrie
5662        let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
5663        trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
5664
5665        // Upper trie should now have a branch at 0x1
5666        ctx.assert_upper_subtrie(&trie)
5667            .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
5668            .has_no_value(&leaf1_path)
5669            .has_no_value(&leaf2_path);
5670
5671        // Add leaf 0x1245 - this should cause a branch and create the 0x12 subtrie
5672        let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x4, 0x5], 3);
5673        trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
5674
5675        // Verify lower subtrie at 0x12 exists with correct structure
5676        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5677            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
5678            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
5679            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::from_nibbles([0x5]))
5680            .has_value(&leaf2_path, &value2)
5681            .has_value(&leaf3_path, &value3);
5682
5683        // Add leaf 0x1334 - this should create another lower subtrie
5684        let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x3, 0x3, 0x4], 4);
5685        trie.update_leaf(leaf4_path, value4.clone(), DefaultTrieNodeProvider).unwrap();
5686
5687        // Verify lower subtrie at 0x13 exists with correct values
5688        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x3]))
5689            .has_value(&leaf1_path, &value1)
5690            .has_value(&leaf4_path, &value4);
5691
5692        // Verify the 0x12 subtrie still has its values
5693        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5694            .has_value(&leaf2_path, &value2)
5695            .has_value(&leaf3_path, &value3);
5696
5697        // Upper trie has no values
5698        ctx.assert_upper_subtrie(&trie)
5699            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1]))
5700            .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
5701            .has_no_value(&leaf1_path)
5702            .has_no_value(&leaf2_path)
5703            .has_no_value(&leaf3_path)
5704            .has_no_value(&leaf4_path);
5705    }
5706
5707    #[test]
5708    fn test_update_leaf_split_at_level_boundary() {
5709        let ctx = ParallelSparseTrieTestContext;
5710        let mut trie =
5711            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5712
5713        // This test demonstrates what happens when we insert leaves that cause
5714        // splitting exactly at the upper/lower trie boundary (2 nibbles).
5715        //
5716        // Final trie structure:
5717        // Upper trie:
5718        //   0x: Extension { key: 0x12 }
5719        //       └── Subtrie (0x12): pointer to lower subtrie
5720        //
5721        // Lower subtrie (0x12):
5722        //   0x12: Branch { state_mask: 0x4 | 0x8 }
5723        //   ├── 0x122: Leaf { key: 0x4 }
5724        //   └── 0x123: Leaf { key: 0x4 }
5725
5726        // First insert a leaf that ends exactly at the boundary (2 nibbles)
5727        let (first_leaf_path, first_value) = ctx.create_test_leaf([0x1, 0x2, 0x2, 0x4], 1);
5728
5729        trie.update_leaf(first_leaf_path, first_value.clone(), DefaultTrieNodeProvider).unwrap();
5730
5731        // In an empty trie, the first leaf becomes the root, regardless of path length
5732        ctx.assert_upper_subtrie(&trie)
5733            .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x2, 0x4]))
5734            .has_value(&first_leaf_path, &first_value);
5735
5736        // Now insert another leaf that shares the same 2-nibble prefix
5737        let (second_leaf_path, second_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
5738
5739        trie.update_leaf(second_leaf_path, second_value.clone(), DefaultTrieNodeProvider).unwrap();
5740
5741        // Now both leaves should be in a lower subtrie at index [0x1, 0x2]
5742        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5743            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x2, 0x3])
5744            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x2]), &Nibbles::from_nibbles([0x4]))
5745            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
5746            .has_value(&first_leaf_path, &first_value)
5747            .has_value(&second_leaf_path, &second_value);
5748
5749        // Upper subtrie should no longer have these values
5750        ctx.assert_upper_subtrie(&trie)
5751            .has_no_value(&first_leaf_path)
5752            .has_no_value(&second_leaf_path);
5753    }
5754
5755    #[test]
5756    fn test_update_subtrie_with_multiple_leaves() {
5757        let ctx = ParallelSparseTrieTestContext;
5758        let mut trie =
5759            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5760
5761        // First, add multiple leaves that will create a subtrie structure
5762        // All leaves share the prefix [0x1, 0x2] to ensure they create a subtrie
5763        //
5764        // This should result in a trie with the following structure:
5765        // 0x: Extension { key: 0x12 }
5766        //  └── Subtrie (0x12):
5767        //      0x12: Branch { state_mask: 0x3 | 0x4 }
5768        //      ├── 0x123: Branch { state_mask: 0x4 | 0x5 }
5769        //      │   ├── 0x1234: Leaf { key: 0x }
5770        //      │   └── 0x1235: Leaf { key: 0x }
5771        //      └── 0x124: Branch { state_mask: 0x6 | 0x7 }
5772        //          ├── 0x1246: Leaf { key: 0x }
5773        //          └── 0x1247: Leaf { key: 0x }
5774        let leaves = ctx.create_test_leaves(&[
5775            &[0x1, 0x2, 0x3, 0x4],
5776            &[0x1, 0x2, 0x3, 0x5],
5777            &[0x1, 0x2, 0x4, 0x6],
5778            &[0x1, 0x2, 0x4, 0x7],
5779        ]);
5780
5781        // Insert all leaves
5782        ctx.update_leaves(&mut trie, leaves.clone());
5783
5784        // Verify the upper subtrie has an extension node at the root with key 0x12
5785        ctx.assert_upper_subtrie(&trie)
5786            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
5787
5788        // Verify the subtrie structure using fluent assertions
5789        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5790            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
5791            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
5792            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &[0x6, 0x7])
5793            .has_value(&leaves[0].0, &leaves[0].1)
5794            .has_value(&leaves[1].0, &leaves[1].1)
5795            .has_value(&leaves[2].0, &leaves[2].1)
5796            .has_value(&leaves[3].0, &leaves[3].1);
5797
5798        // Now update one of the leaves with a new value
5799        let updated_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]);
5800        let (_, updated_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 100);
5801
5802        trie.update_leaf(updated_path, updated_value.clone(), DefaultTrieNodeProvider).unwrap();
5803
5804        // Verify the subtrie structure is maintained and value is updated
5805        // The branch structure should remain the same and all values should be present
5806        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5807            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
5808            .has_value(&updated_path, &updated_value)
5809            .has_value(&leaves[1].0, &leaves[1].1)
5810            .has_value(&leaves[2].0, &leaves[2].1)
5811            .has_value(&leaves[3].0, &leaves[3].1);
5812
5813        // Add a new leaf that extends an existing branch
5814        let (new_leaf_path, new_leaf_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 200);
5815
5816        trie.update_leaf(new_leaf_path, new_leaf_value.clone(), DefaultTrieNodeProvider).unwrap();
5817
5818        // Verify the branch at [0x1, 0x2, 0x3] now has an additional child
5819        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5820            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6])
5821            .has_value(&new_leaf_path, &new_leaf_value);
5822    }
5823
5824    #[test]
5825    fn test_update_subtrie_extension_node_subtrie() {
5826        let ctx = ParallelSparseTrieTestContext;
5827        let mut trie =
5828            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5829
5830        // All leaves share the prefix [0x1, 0x2] to ensure they create a subtrie
5831        //
5832        // This should result in a trie with the following structure
5833        // 0x: Extension { key: 0x123 }
5834        //  └── Subtrie (0x12):
5835        //      0x123: Branch { state_mask: 0x3 | 0x4 }
5836        //      ├── 0x123: Leaf { key: 0x4 }
5837        //      └── 0x124: Leaf { key: 0x5 }
5838        let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x3, 0x5]]);
5839
5840        // Insert all leaves
5841        ctx.update_leaves(&mut trie, leaves.clone());
5842
5843        // Verify the upper subtrie has an extension node at the root with key 0x123
5844        ctx.assert_upper_subtrie(&trie)
5845            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
5846
5847        // Verify the lower subtrie structure
5848        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5849            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
5850            .has_value(&leaves[0].0, &leaves[0].1)
5851            .has_value(&leaves[1].0, &leaves[1].1);
5852    }
5853
5854    #[test]
5855    fn update_subtrie_extension_node_cross_level() {
5856        let ctx = ParallelSparseTrieTestContext;
5857        let mut trie =
5858            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5859
5860        // First, add multiple leaves that will create a subtrie structure
5861        // All leaves share the prefix [0x1, 0x2] to ensure they create a branch node and subtrie
5862        //
5863        // This should result in a trie with the following structure
5864        // 0x: Extension { key: 0x12 }
5865        //  └── Subtrie (0x12):
5866        //      0x12: Branch { state_mask: 0x3 | 0x4 }
5867        //      ├── 0x123: Leaf { key: 0x4 }
5868        //      └── 0x124: Leaf { key: 0x5 }
5869        let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x4, 0x5]]);
5870
5871        // Insert all leaves
5872        ctx.update_leaves(&mut trie, leaves.clone());
5873
5874        // Verify the upper subtrie has an extension node at the root with key 0x12
5875        ctx.assert_upper_subtrie(&trie)
5876            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
5877
5878        // Verify the lower subtrie structure
5879        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
5880            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
5881            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
5882            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::from_nibbles([0x5]))
5883            .has_value(&leaves[0].0, &leaves[0].1)
5884            .has_value(&leaves[1].0, &leaves[1].1);
5885    }
5886
5887    #[test]
5888    fn test_update_single_nibble_paths() {
5889        let ctx = ParallelSparseTrieTestContext;
5890        let mut trie =
5891            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5892
5893        // Test edge case: single nibble paths that create branches in upper trie
5894        //
5895        // Final trie structure:
5896        // Upper trie:
5897        //   0x: Branch { state_mask: 0x1 | 0x2 | 0x4 | 0x8 }
5898        //   ├── 0x0: Leaf { key: 0x }
5899        //   ├── 0x1: Leaf { key: 0x }
5900        //   ├── 0x2: Leaf { key: 0x }
5901        //   └── 0x3: Leaf { key: 0x }
5902
5903        // Insert leaves with single nibble paths
5904        let (leaf1_path, value1) = ctx.create_test_leaf([0x0], 1);
5905        let (leaf2_path, value2) = ctx.create_test_leaf([0x1], 2);
5906        let (leaf3_path, value3) = ctx.create_test_leaf([0x2], 3);
5907        let (leaf4_path, value4) = ctx.create_test_leaf([0x3], 4);
5908
5909        ctx.update_leaves(
5910            &mut trie,
5911            [
5912                (leaf1_path, value1.clone()),
5913                (leaf2_path, value2.clone()),
5914                (leaf3_path, value3.clone()),
5915                (leaf4_path, value4.clone()),
5916            ],
5917        );
5918
5919        // Verify upper trie has a branch at root with 4 children
5920        ctx.assert_upper_subtrie(&trie)
5921            .has_branch(&Nibbles::default(), &[0x0, 0x1, 0x2, 0x3])
5922            .has_leaf(&Nibbles::from_nibbles([0x0]), &Nibbles::default())
5923            .has_leaf(&Nibbles::from_nibbles([0x1]), &Nibbles::default())
5924            .has_leaf(&Nibbles::from_nibbles([0x2]), &Nibbles::default())
5925            .has_leaf(&Nibbles::from_nibbles([0x3]), &Nibbles::default())
5926            .has_value(&leaf1_path, &value1)
5927            .has_value(&leaf2_path, &value2)
5928            .has_value(&leaf3_path, &value3)
5929            .has_value(&leaf4_path, &value4);
5930    }
5931
5932    #[test]
5933    fn test_update_deep_extension_chain() {
5934        let ctx = ParallelSparseTrieTestContext;
5935        let mut trie =
5936            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5937
5938        // Test edge case: deep extension chains that span multiple levels
5939        //
5940        // Final trie structure:
5941        // Upper trie:
5942        //   0x: Extension { key: 0x111111 }
5943        //       └── Subtrie (0x11): pointer to lower subtrie
5944        //
5945        // Lower subtrie (0x11):
5946        //   0x111111: Branch { state_mask: 0x1 | 0x2 }
5947        //   ├── 0x1111110: Leaf { key: 0x }
5948        //   └── 0x1111111: Leaf { key: 0x }
5949
5950        // Create leaves with a long common prefix
5951        let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0], 1);
5952        let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1], 2);
5953
5954        ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
5955
5956        // Verify upper trie has extension with the full common prefix
5957        ctx.assert_upper_subtrie(&trie).has_extension(
5958            &Nibbles::default(),
5959            &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
5960        );
5961
5962        // Verify lower subtrie has branch structure
5963        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x1]))
5964            .has_branch(&Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]), &[0x0, 0x1])
5965            .has_leaf(
5966                &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0]),
5967                &Nibbles::default(),
5968            )
5969            .has_leaf(
5970                &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
5971                &Nibbles::default(),
5972            )
5973            .has_value(&leaf1_path, &value1)
5974            .has_value(&leaf2_path, &value2);
5975    }
5976
5977    #[test]
5978    fn test_update_branch_with_all_nibbles() {
5979        let ctx = ParallelSparseTrieTestContext;
5980        let mut trie =
5981            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
5982
5983        // Test edge case: branch node with all 16 possible nibble children
5984        //
5985        // Final trie structure:
5986        // Upper trie:
5987        //   0x: Extension { key: 0xA }
5988        //       └── Subtrie (0xA0): pointer to lower subtrie
5989        //
5990        // Lower subtrie (0xA0):
5991        //   0xA0: Branch { state_mask: 0xFFFF } (all 16 children)
5992        //   ├── 0xA00: Leaf { key: 0x }
5993        //   ├── 0xA01: Leaf { key: 0x }
5994        //   ├── 0xA02: Leaf { key: 0x }
5995        //   ... (all nibbles 0x0 through 0xF)
5996        //   └── 0xA0F: Leaf { key: 0x }
5997
5998        // Create leaves for all 16 possible nibbles
5999        let mut leaves = Vec::new();
6000        for nibble in 0x0..=0xF {
6001            let (path, value) = ctx.create_test_leaf([0xA, 0x0, nibble], nibble as u64 + 1);
6002            leaves.push((path, value));
6003        }
6004
6005        // Insert all leaves
6006        ctx.update_leaves(&mut trie, leaves.iter().cloned());
6007
6008        // Verify upper trie structure
6009        ctx.assert_upper_subtrie(&trie)
6010            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0x0]));
6011
6012        // Verify lower subtrie has branch with all 16 children
6013        let mut subtrie_assert =
6014            ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0x0])).has_branch(
6015                &Nibbles::from_nibbles([0xA, 0x0]),
6016                &[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
6017            );
6018
6019        // Verify all leaves exist
6020        for (i, (path, value)) in leaves.iter().enumerate() {
6021            subtrie_assert = subtrie_assert
6022                .has_leaf(&Nibbles::from_nibbles([0xA, 0x0, i as u8]), &Nibbles::default())
6023                .has_value(path, value);
6024        }
6025    }
6026
6027    #[test]
6028    fn test_update_creates_multiple_subtries() {
6029        let ctx = ParallelSparseTrieTestContext;
6030        let mut trie =
6031            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6032
6033        // Test edge case: updates that create multiple subtries at once
6034        //
6035        // Final trie structure:
6036        // Upper trie:
6037        //   0x: Extension { key: 0x0 }
6038        //       └── 0x0: Branch { state_mask: 0xF }
6039        //           ├── Subtrie (0x00): pointer
6040        //           ├── Subtrie (0x01): pointer
6041        //           ├── Subtrie (0x02): pointer
6042        //           └── Subtrie (0x03): pointer
6043        //
6044        // Each lower subtrie has leaves:
6045        //   0xXY: Leaf { key: 0xZ... }
6046
6047        // Create leaves that will force multiple subtries
6048        let leaves = [
6049            ctx.create_test_leaf([0x0, 0x0, 0x1, 0x2], 1),
6050            ctx.create_test_leaf([0x0, 0x1, 0x3, 0x4], 2),
6051            ctx.create_test_leaf([0x0, 0x2, 0x5, 0x6], 3),
6052            ctx.create_test_leaf([0x0, 0x3, 0x7, 0x8], 4),
6053        ];
6054
6055        // Insert all leaves
6056        ctx.update_leaves(&mut trie, leaves.iter().cloned());
6057
6058        // Verify upper trie has extension then branch
6059        ctx.assert_upper_subtrie(&trie)
6060            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x0]))
6061            .has_branch(&Nibbles::from_nibbles([0x0]), &[0x0, 0x1, 0x2, 0x3]);
6062
6063        // Verify each subtrie exists and contains its leaf
6064        for (i, (leaf_path, leaf_value)) in leaves.iter().enumerate() {
6065            let subtrie_path = Nibbles::from_nibbles([0x0, i as u8]);
6066            ctx.assert_subtrie(&trie, subtrie_path)
6067                .has_leaf(
6068                    &subtrie_path,
6069                    &Nibbles::from_nibbles(match i {
6070                        0 => vec![0x1, 0x2],
6071                        1 => vec![0x3, 0x4],
6072                        2 => vec![0x5, 0x6],
6073                        3 => vec![0x7, 0x8],
6074                        _ => unreachable!(),
6075                    }),
6076                )
6077                .has_value(leaf_path, leaf_value);
6078        }
6079    }
6080
6081    #[test]
6082    fn test_update_extension_to_branch_transformation() {
6083        let ctx = ParallelSparseTrieTestContext;
6084        let mut trie =
6085            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6086
6087        // Test edge case: extension node transforms to branch when split
6088        //
6089        // Initial state after first two leaves:
6090        // Upper trie:
6091        //   0x: Extension { key: 0xFF0 }
6092        //       └── Subtrie (0xFF): pointer
6093        //
6094        // After third leaf (0xF0...):
6095        // Upper trie:
6096        //   0x: Extension { key: 0xF }
6097        //       └── 0xF: Branch { state_mask: 0x10 | 0x8000 }
6098        //           ├── Subtrie (0xF0): pointer
6099        //           └── Subtrie (0xFF): pointer
6100
6101        // First two leaves share prefix 0xFF0
6102        let (leaf1_path, value1) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x1], 1);
6103        let (leaf2_path, value2) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x2], 2);
6104        let (leaf3_path, value3) = ctx.create_test_leaf([0xF, 0x0, 0x0, 0x3], 3);
6105
6106        ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
6107
6108        // Verify initial extension structure
6109        ctx.assert_upper_subtrie(&trie)
6110            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF, 0xF, 0x0]));
6111
6112        // Add leaf that splits the extension
6113        ctx.update_leaves(&mut trie, [(leaf3_path, value3.clone())]);
6114
6115        // Verify transformed structure
6116        ctx.assert_upper_subtrie(&trie)
6117            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF]))
6118            .has_branch(&Nibbles::from_nibbles([0xF]), &[0x0, 0xF]);
6119
6120        // Verify subtries
6121        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
6122            .has_branch(&Nibbles::from_nibbles([0xF, 0xF, 0x0]), &[0x1, 0x2])
6123            .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x1]), &Nibbles::default())
6124            .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x2]), &Nibbles::default())
6125            .has_value(&leaf1_path, &value1)
6126            .has_value(&leaf2_path, &value2);
6127
6128        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0x0]))
6129            .has_leaf(&Nibbles::from_nibbles([0xF, 0x0]), &Nibbles::from_nibbles([0x0, 0x3]))
6130            .has_value(&leaf3_path, &value3);
6131    }
6132
6133    #[test]
6134    fn test_update_upper_extension_reveal_lower_hash_node() {
6135        let ctx = ParallelSparseTrieTestContext;
6136
6137        // Test edge case: extension pointing to hash node that gets updated to branch
6138        // and reveals the hash node from lower trie
6139        //
6140        // Setup:
6141        // Upper trie:
6142        //   0x: Extension { key: 0xAB }
6143        //       └── Subtrie (0xAB): pointer
6144        // Lower trie (0xAB):
6145        //   0xAB: Hash
6146        //
6147        // After update:
6148        // Upper trie:
6149        //   0x: Extension { key: 0xA }
6150        //       └── 0xA: Branch { state_mask: 0b100000000001 }
6151        //                ├── 0xA0: Leaf { value: ... }
6152        //                └── 0xAB: pointer
6153        // Lower trie (0xAB):
6154        //   0xAB: Branch { state_mask: 0b11 }
6155        //         ├── 0xAB1: Hash
6156        //         └── 0xAB2: Hash
6157
6158        // Create a mock provider that will provide the hash node
6159        let mut provider = MockTrieNodeProvider::new();
6160
6161        // Create revealed branch which will get revealed and add it to the mock provider
6162        let child_hashes = [
6163            RlpNode::word_rlp(&B256::repeat_byte(0x11)),
6164            RlpNode::word_rlp(&B256::repeat_byte(0x22)),
6165        ];
6166        let revealed_branch = create_branch_node_with_children(&[0x1, 0x2], child_hashes);
6167        let mut encoded = Vec::new();
6168        revealed_branch.encode(&mut encoded);
6169        provider.add_revealed_node(
6170            Nibbles::from_nibbles([0xA, 0xB]),
6171            RevealedNode { node: encoded.into(), tree_mask: None, hash_mask: None },
6172        );
6173
6174        let mut trie = new_test_trie(
6175            [
6176                (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0xA, 0xB]))),
6177                (Nibbles::from_nibbles([0xA, 0xB]), SparseNode::Hash(B256::repeat_byte(0x42))),
6178            ]
6179            .into_iter(),
6180        );
6181
6182        // Now add a leaf that will force the hash node to become a branch
6183        let (leaf_path, value) = ctx.create_test_leaf([0xA, 0x0], 1);
6184        trie.update_leaf(leaf_path, value, provider).unwrap();
6185
6186        // Verify the structure: extension should now terminate in a branch on the upper trie
6187        ctx.assert_upper_subtrie(&trie)
6188            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA]))
6189            .has_branch(&Nibbles::from_nibbles([0xA]), &[0x0, 0xB]);
6190
6191        // Verify the lower trie now has a branch structure
6192        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0xB]))
6193            .has_branch(&Nibbles::from_nibbles([0xA, 0xB]), &[0x1, 0x2])
6194            .has_hash(&Nibbles::from_nibbles([0xA, 0xB, 0x1]), &B256::repeat_byte(0x11))
6195            .has_hash(&Nibbles::from_nibbles([0xA, 0xB, 0x2]), &B256::repeat_byte(0x22));
6196    }
6197
6198    #[test]
6199    fn test_update_long_shared_prefix_at_boundary() {
6200        let ctx = ParallelSparseTrieTestContext;
6201        let mut trie =
6202            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6203
6204        // Test edge case: leaves with long shared prefix that ends exactly at 2-nibble boundary
6205        //
6206        // Final trie structure:
6207        // Upper trie:
6208        //   0x: Extension { key: 0xAB }
6209        //       └── Subtrie (0xAB): pointer to lower subtrie
6210        //
6211        // Lower subtrie (0xAB):
6212        //   0xAB: Branch { state_mask: 0x1000 | 0x2000 }
6213        //   ├── 0xABC: Leaf { key: 0xDEF }
6214        //   └── 0xABD: Leaf { key: 0xEF0 }
6215
6216        // Create leaves that share exactly 2 nibbles
6217        let (leaf1_path, value1) = ctx.create_test_leaf([0xA, 0xB, 0xC, 0xD, 0xE, 0xF], 1);
6218        let (leaf2_path, value2) = ctx.create_test_leaf([0xA, 0xB, 0xD, 0xE, 0xF, 0x0], 2);
6219
6220        trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
6221        trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
6222
6223        // Verify upper trie structure
6224        ctx.assert_upper_subtrie(&trie)
6225            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0xB]));
6226
6227        // Verify lower subtrie structure
6228        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0xB]))
6229            .has_branch(&Nibbles::from_nibbles([0xA, 0xB]), &[0xC, 0xD])
6230            .has_leaf(
6231                &Nibbles::from_nibbles([0xA, 0xB, 0xC]),
6232                &Nibbles::from_nibbles([0xD, 0xE, 0xF]),
6233            )
6234            .has_leaf(
6235                &Nibbles::from_nibbles([0xA, 0xB, 0xD]),
6236                &Nibbles::from_nibbles([0xE, 0xF, 0x0]),
6237            )
6238            .has_value(&leaf1_path, &value1)
6239            .has_value(&leaf2_path, &value2);
6240    }
6241
6242    #[test]
6243    fn test_update_branch_to_extension_collapse() {
6244        let ctx = ParallelSparseTrieTestContext;
6245        let mut trie =
6246            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6247
6248        // Test creating a trie with leaves that share a long common prefix
6249        //
6250        // Initial state with 3 leaves (0x1234, 0x2345, 0x2356):
6251        // Upper trie:
6252        //   0x: Branch { state_mask: 0x6 }
6253        //       ├── 0x1: Leaf { key: 0x234 }
6254        //       └── 0x2: Extension { key: 0x3 }
6255        //           └── Subtrie (0x23): pointer
6256        // Lower subtrie (0x23):
6257        //   0x23: Branch { state_mask: 0x30 }
6258        //       ├── 0x234: Leaf { key: 0x5 }
6259        //       └── 0x235: Leaf { key: 0x6 }
6260        //
6261        // Then we create a new trie with leaves (0x1234, 0x1235, 0x1236):
6262        // Expected structure:
6263        // Upper trie:
6264        //   0x: Extension { key: 0x123 }
6265        //       └── Subtrie (0x12): pointer
6266        // Lower subtrie (0x12):
6267        //   0x123: Branch { state_mask: 0x70 } // bits 4, 5, 6 set
6268        //       ├── 0x1234: Leaf { key: 0x }
6269        //       ├── 0x1235: Leaf { key: 0x }
6270        //       └── 0x1236: Leaf { key: 0x }
6271
6272        // Create initial leaves
6273        let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
6274        let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
6275        let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
6276
6277        trie.update_leaf(leaf1_path, value1, DefaultTrieNodeProvider).unwrap();
6278        trie.update_leaf(leaf2_path, value2, DefaultTrieNodeProvider).unwrap();
6279        trie.update_leaf(leaf3_path, value3, DefaultTrieNodeProvider).unwrap();
6280
6281        // Verify initial structure has branch at root
6282        ctx.assert_upper_subtrie(&trie).has_branch(&Nibbles::default(), &[0x1, 0x2]);
6283
6284        // Now update to create a pattern where extension is more efficient
6285        // Replace leaves to all share prefix 0x123
6286        let (new_leaf1_path, new_value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 10);
6287        let (new_leaf2_path, new_value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 11);
6288        let (new_leaf3_path, new_value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 12);
6289
6290        // Clear and add new leaves
6291        let mut trie =
6292            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6293        trie.update_leaf(new_leaf1_path, new_value1.clone(), DefaultTrieNodeProvider).unwrap();
6294        trie.update_leaf(new_leaf2_path, new_value2.clone(), DefaultTrieNodeProvider).unwrap();
6295        trie.update_leaf(new_leaf3_path, new_value3.clone(), DefaultTrieNodeProvider).unwrap();
6296
6297        // Verify new structure has extension
6298        ctx.assert_upper_subtrie(&trie)
6299            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6300
6301        // Verify lower subtrie path was correctly updated to 0x123
6302        ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
6303
6304        // Verify lower subtrie - all three leaves should be properly inserted
6305        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6306            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6]) // All three children
6307            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &Nibbles::default())
6308            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &Nibbles::default())
6309            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x6]), &Nibbles::default())
6310            .has_value(&new_leaf1_path, &new_value1)
6311            .has_value(&new_leaf2_path, &new_value2)
6312            .has_value(&new_leaf3_path, &new_value3);
6313    }
6314
6315    #[test]
6316    fn test_update_shared_prefix_patterns() {
6317        let ctx = ParallelSparseTrieTestContext;
6318        let mut trie =
6319            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6320
6321        // Test edge case: different patterns of shared prefixes
6322        //
6323        // Final trie structure:
6324        // Upper trie:
6325        //   0x: Branch { state_mask: 0x6 }
6326        //       ├── 0x1: Leaf { key: 0x234 }
6327        //       └── 0x2: Extension { key: 0x3 }
6328        //           └── Subtrie (0x23): pointer
6329        //
6330        // Lower subtrie (0x23):
6331        //   0x23: Branch { state_mask: 0x10 | 0x20 }
6332        //   ├── 0x234: Leaf { key: 0x5 }
6333        //   └── 0x235: Leaf { key: 0x6 }
6334
6335        // Create leaves with different shared prefix patterns
6336        let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
6337        let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
6338        let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
6339
6340        trie.update_leaf(leaf1_path, value1, DefaultTrieNodeProvider).unwrap();
6341        trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
6342        trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
6343
6344        // Verify upper trie structure
6345        ctx.assert_upper_subtrie(&trie)
6346            .has_branch(&Nibbles::default(), &[0x1, 0x2])
6347            .has_leaf(&Nibbles::from_nibbles([0x1]), &Nibbles::from_nibbles([0x2, 0x3, 0x4]))
6348            .has_extension(&Nibbles::from_nibbles([0x2]), &Nibbles::from_nibbles([0x3]));
6349
6350        // Verify lower subtrie structure
6351        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x2, 0x3]))
6352            .has_branch(&Nibbles::from_nibbles([0x2, 0x3]), &[0x4, 0x5])
6353            .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x4]), &Nibbles::from_nibbles([0x5]))
6354            .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x5]), &Nibbles::from_nibbles([0x6]))
6355            .has_value(&leaf2_path, &value2)
6356            .has_value(&leaf3_path, &value3);
6357    }
6358
6359    #[test]
6360    fn test_progressive_branch_creation() {
6361        let ctx = ParallelSparseTrieTestContext;
6362        let mut trie =
6363            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6364
6365        // Test starting with a single leaf and progressively adding leaves
6366        // that create branch nodes at shorter and shorter paths
6367        //
6368        // Step 1: Add leaf at 0x12345
6369        // Upper trie:
6370        //   0x: Leaf { key: 0x12345 }
6371        //
6372        // Step 2: Add leaf at 0x12346
6373        // Upper trie:
6374        //   0x: Extension { key: 0x1234 }
6375        //       └── Subtrie (0x12): pointer
6376        // Lower subtrie (0x12):
6377        //   0x1234: Branch { state_mask: 0x60 }  // bits 5 and 6 set
6378        //       ├── 0x12345: Leaf { key: 0x }
6379        //       └── 0x12346: Leaf { key: 0x }
6380        //
6381        // Step 3: Add leaf at 0x1235
6382        // Lower subtrie (0x12) updates to:
6383        //   0x123: Branch { state_mask: 0x30 }  // bits 4 and 5 set
6384        //       ├── 0x1234: Branch { state_mask: 0x60 }
6385        //       │   ├── 0x12345: Leaf { key: 0x }
6386        //       │   └── 0x12346: Leaf { key: 0x }
6387        //       └── 0x1235: Leaf { key: 0x }
6388        //
6389        // Step 4: Add leaf at 0x124
6390        // Lower subtrie (0x12) updates to:
6391        //   0x12: Branch { state_mask: 0x18 }  // bits 3 and 4 set
6392        //       ├── 0x123: Branch { state_mask: 0x30 }
6393        //       │   ├── 0x1234: Branch { state_mask: 0x60 }
6394        //       │   │   ├── 0x12345: Leaf { key: 0x }
6395        //       │   │   └── 0x12346: Leaf { key: 0x }
6396        //       │   └── 0x1235: Leaf { key: 0x }
6397        //       └── 0x124: Leaf { key: 0x }
6398
6399        // Step 1: Add first leaf - initially stored as leaf in upper trie
6400        let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x5], 1);
6401        trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
6402
6403        // Verify leaf node in upper trie (optimized single-leaf case)
6404        ctx.assert_upper_subtrie(&trie)
6405            .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]))
6406            .has_value(&leaf1_path, &value1);
6407
6408        // Step 2: Add leaf at 0x12346 - creates branch at 0x1234
6409        let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x6], 2);
6410        trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
6411
6412        // Verify extension now goes to 0x1234
6413        ctx.assert_upper_subtrie(&trie)
6414            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
6415
6416        // Verify subtrie path updated to 0x1234
6417        ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3, 0x4]);
6418
6419        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6420            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6421            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]), &Nibbles::default())
6422            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x6]), &Nibbles::default())
6423            .has_value(&leaf1_path, &value1)
6424            .has_value(&leaf2_path, &value2);
6425
6426        // Step 3: Add leaf at 0x1235 - creates branch at 0x123
6427        let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 3);
6428        trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
6429
6430        // Verify extension now goes to 0x123
6431        ctx.assert_upper_subtrie(&trie)
6432            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6433
6434        // Verify subtrie path updated to 0x123
6435        ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
6436
6437        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6438            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6439            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6440            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &Nibbles::default())
6441            .has_value(&leaf1_path, &value1)
6442            .has_value(&leaf2_path, &value2)
6443            .has_value(&leaf3_path, &value3);
6444
6445        // Step 4: Add leaf at 0x124 - creates branch at 0x12 (subtrie root)
6446        let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x2, 0x4], 4);
6447        trie.update_leaf(leaf4_path, value4.clone(), DefaultTrieNodeProvider).unwrap();
6448
6449        // Verify extension now goes to 0x12
6450        ctx.assert_upper_subtrie(&trie)
6451            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6452
6453        // Verify subtrie path updated to 0x12
6454        ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2]);
6455
6456        // Verify final structure
6457        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6458            .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6459            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6460            .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6461            .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::default())
6462            .has_value(&leaf1_path, &value1)
6463            .has_value(&leaf2_path, &value2)
6464            .has_value(&leaf3_path, &value3)
6465            .has_value(&leaf4_path, &value4);
6466    }
6467
6468    #[test]
6469    fn test_update_max_depth_paths() {
6470        let ctx = ParallelSparseTrieTestContext;
6471        let mut trie =
6472            ParallelSparseTrie::from_root(TrieNode::EmptyRoot, TrieMasks::none(), true).unwrap();
6473
6474        // Test edge case: very long paths (64 nibbles - max for addresses/storage)
6475        //
6476        // Final trie structure:
6477        // Upper trie:
6478        //   0x: Extension { key: 0xFF }
6479        //       └── Subtrie (0xFF): pointer
6480        //
6481        // Lower subtrie (0xFF):
6482        //   Has very long paths with slight differences at the end
6483
6484        // Create two 64-nibble paths that differ only in the last nibble
6485        let mut path1_nibbles = vec![0xF; 63];
6486        path1_nibbles.push(0x0);
6487        let mut path2_nibbles = vec![0xF; 63];
6488        path2_nibbles.push(0x1);
6489
6490        let (leaf1_path, value1) = ctx.create_test_leaf(&path1_nibbles, 1);
6491        let (leaf2_path, value2) = ctx.create_test_leaf(&path2_nibbles, 2);
6492
6493        trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
6494        trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
6495
6496        // The common prefix of 63 F's will create a very long extension
6497        let extension_key = vec![0xF; 63];
6498        ctx.assert_upper_subtrie(&trie)
6499            .has_extension(&Nibbles::default(), &Nibbles::from_nibbles(&extension_key));
6500
6501        // Verify the subtrie has the branch at the end
6502        ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
6503            .has_branch(&Nibbles::from_nibbles(&path1_nibbles[..63]), &[0x0, 0x1])
6504            .has_value(&leaf1_path, &value1)
6505            .has_value(&leaf2_path, &value2);
6506    }
6507
6508    #[test]
6509    fn test_hoodie_block_1_data() {
6510        // Reveal node at path Nibbles(0x) - root branch node
6511        let root_branch_stack = vec![
6512            hex!("a0550b6aba4dd4582a2434d2cbdad8d3007d09f622d7a6e6eaa7a49385823c2fa2"),
6513            hex!("a04788a4975a9e1efd29b834fd80fdfe8a57cc1b1c5ace6d30ce5a36a15e0092b3"),
6514            hex!("a093aeccf87da304e6f7d09edc5d7bd3a552808866d2149dd0940507a8f9bfa910"),
6515            hex!("a08b5b423ba68d0dec2eca1f408076f9170678505eb4a5db2abbbd83bb37666949"),
6516            hex!("a08592f62216af4218098a78acad7cf472a727fb55e6c27d3cfdf2774d4518eb83"),
6517            hex!("a0ef02aeee845cb64c11f85edc1a3094227c26445952554b8a9248915d80c746c3"),
6518            hex!("a0df2529ee3a1ce4df5a758cf17e6a86d0fb5ea22ab7071cf60af6412e9b0a428a"),
6519            hex!("a0acaa1092db69cd5a63676685827b3484c4b80dc1d3361f6073bbb9240101e144"),
6520            hex!("a09c3f2bb2a729d71f246a833353ade65667716bb330e0127a3299a42d11200f93"),
6521            hex!("a0ce978470f4c0b1f8069570563a14d2b79d709add2db4bf22dd9b6aed3271c566"),
6522            hex!("a095f783cd1d464a60e3c8adcadc28c6eb9fec7306664df39553be41dccc909606"),
6523            hex!("a0a9083f5fb914b255e1feb5d951a4dfddacf3c8003ef1d1ec6a13bb6ba5b2ac62"),
6524            hex!("a0fec113d537d8577cd361e0cabf5e95ef58f1cc34318292fdecce9fae57c3e094"),
6525            hex!("a08b7465f5fe8b3e3c0d087cb7521310d4065ef2a0ee43bf73f68dee8a5742b3dd"),
6526            hex!("a0c589aa1ae3d5fd87d8640957f7d5184a4ac06f393b453a8e8ed7e8fba0d385c8"),
6527            hex!("a0b516d6f3352f87beab4ed6e7322f191fc7a147686500ef4de7dd290ad784ef51"),
6528        ];
6529
6530        let root_branch_rlp_stack: Vec<RlpNode> = root_branch_stack
6531            .iter()
6532            .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
6533            .collect();
6534
6535        let root_branch_node = BranchNode::new(
6536            root_branch_rlp_stack,
6537            TrieMask::new(0b1111111111111111), // state_mask: all 16 children present
6538        );
6539
6540        let root_branch_masks = TrieMasks {
6541            hash_mask: Some(TrieMask::new(0b1111111111111111)),
6542            tree_mask: Some(TrieMask::new(0b1111111111111111)),
6543        };
6544
6545        let mut trie = ParallelSparseTrie::from_root(
6546            TrieNode::Branch(root_branch_node),
6547            root_branch_masks,
6548            true,
6549        )
6550        .unwrap();
6551
6552        // Reveal node at path Nibbles(0x3) - branch node
6553        let branch_0x3_stack = vec![
6554            hex!("a09da7d9755fe0c558b3c3de9fdcdf9f28ae641f38c9787b05b73ab22ae53af3e2"),
6555            hex!("a0d9990bf0b810d1145ecb2b011fd68c63cc85564e6724166fd4a9520180706e5f"),
6556            hex!("a0f60eb4b12132a40df05d9bbdb88bbde0185a3f097f3c76bf4200c23eda26cf86"),
6557            hex!("a0ca976997ddaf06f18992f6207e4f6a05979d07acead96568058789017cc6d06b"),
6558            hex!("a04d78166b48044fdc28ed22d2fd39c8df6f8aaa04cb71d3a17286856f6893ff83"),
6559            hex!("a021d4f90c34d3f1706e78463b6482bca77a3aa1cd059a3f326c42a1cfd30b9b60"),
6560            hex!("a0fc3b71c33e2e6b77c5e494c1db7fdbb447473f003daf378c7a63ba9bf3f0049d"),
6561            hex!("a0e33ed2be194a3d93d343e85642447c93a9d0cfc47a016c2c23d14c083be32a7c"),
6562            hex!("a07b8e7a21c1178d28074f157b50fca85ee25c12568ff8e9706dcbcdacb77bf854"),
6563            hex!("a0973274526811393ea0bf4811ca9077531db00d06b86237a2ecd683f55ba4bcb0"),
6564            hex!("a03a93d726d7487874e51b52d8d534c63aa2a689df18e3b307c0d6cb0a388b00f3"),
6565            hex!("a06aa67101d011d1c22fe739ef83b04b5214a3e2f8e1a2625d8bfdb116b447e86f"),
6566            hex!("a02dd545b33c62d33a183e127a08a4767fba891d9f3b94fc20a2ca02600d6d1fff"),
6567            hex!("a0fe6db87d00f06d53bff8169fa497571ff5af1addfb715b649b4d79dd3e394b04"),
6568            hex!("a0d9240a9d2d5851d05a97ff3305334dfdb0101e1e321fc279d2bb3cad6afa8fc8"),
6569            hex!("a01b69c6ab5173de8a8ec53a6ebba965713a4cc7feb86cb3e230def37c230ca2b2"),
6570        ];
6571
6572        let branch_0x3_rlp_stack: Vec<RlpNode> = branch_0x3_stack
6573            .iter()
6574            .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
6575            .collect();
6576
6577        let branch_0x3_node = BranchNode::new(
6578            branch_0x3_rlp_stack,
6579            TrieMask::new(0b1111111111111111), // state_mask: all 16 children present
6580        );
6581
6582        let branch_0x3_masks = TrieMasks {
6583            hash_mask: Some(TrieMask::new(0b0100010000010101)),
6584            tree_mask: Some(TrieMask::new(0b0100000000000000)),
6585        };
6586
6587        // Reveal node at path Nibbles(0x37) - leaf node
6588        let leaf_path = Nibbles::from_nibbles([0x3, 0x7]);
6589        let leaf_key = Nibbles::unpack(
6590            &hex!("d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42")[..],
6591        );
6592        let leaf_value = hex!("f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0f57acd40259872606d76197ef052f3d35588dadf919ee1f0e3cb9b62d3f4b02c").to_vec();
6593
6594        let leaf_node = LeafNode::new(leaf_key, leaf_value);
6595        let leaf_masks = TrieMasks::none();
6596
6597        trie.reveal_nodes(vec![
6598            RevealedSparseNode {
6599                path: Nibbles::from_nibbles([0x3]),
6600                node: TrieNode::Branch(branch_0x3_node),
6601                masks: branch_0x3_masks,
6602            },
6603            RevealedSparseNode {
6604                path: leaf_path,
6605                node: TrieNode::Leaf(leaf_node),
6606                masks: leaf_masks,
6607            },
6608        ])
6609        .unwrap();
6610
6611        // Update leaf with its new value
6612        let mut leaf_full_path = leaf_path;
6613        leaf_full_path.extend(&leaf_key);
6614
6615        let leaf_new_value = vec![
6616            248, 68, 1, 128, 160, 224, 163, 152, 169, 122, 160, 155, 102, 53, 41, 0, 47, 28, 205,
6617            190, 199, 5, 215, 108, 202, 22, 138, 70, 196, 178, 193, 208, 18, 96, 95, 63, 238, 160,
6618            245, 122, 205, 64, 37, 152, 114, 96, 109, 118, 25, 126, 240, 82, 243, 211, 85, 136,
6619            218, 223, 145, 158, 225, 240, 227, 203, 155, 98, 211, 244, 176, 44,
6620        ];
6621
6622        trie.update_leaf(leaf_full_path, leaf_new_value.clone(), DefaultTrieNodeProvider).unwrap();
6623
6624        // Sanity checks before calculating the root
6625        assert_eq!(
6626            Some(&leaf_new_value),
6627            trie.lower_subtrie_for_path(&leaf_path).unwrap().inner.values.get(&leaf_full_path)
6628        );
6629        assert!(trie.upper_subtrie.inner.values.is_empty());
6630
6631        // Assert the root hash matches the expected value
6632        let expected_root =
6633            b256!("0x29b07de8376e9ce7b3a69e9b102199869514d3f42590b5abc6f7d48ec9b8665c");
6634        assert_eq!(trie.root(), expected_root);
6635    }
6636
6637    #[test]
6638    fn find_leaf_existing_leaf() {
6639        // Create a simple trie with one leaf
6640        let provider = DefaultTrieNodeProvider;
6641        let mut sparse = ParallelSparseTrie::default();
6642        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
6643        let value = b"test_value".to_vec();
6644
6645        sparse.update_leaf(path, value.clone(), &provider).unwrap();
6646
6647        // Check that the leaf exists
6648        let result = sparse.find_leaf(&path, None);
6649        assert_matches!(result, Ok(LeafLookup::Exists));
6650
6651        // Check with expected value matching
6652        let result = sparse.find_leaf(&path, Some(&value));
6653        assert_matches!(result, Ok(LeafLookup::Exists));
6654    }
6655
6656    #[test]
6657    fn find_leaf_value_mismatch() {
6658        // Create a simple trie with one leaf
6659        let provider = DefaultTrieNodeProvider;
6660        let mut sparse = ParallelSparseTrie::default();
6661        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
6662        let value = b"test_value".to_vec();
6663        let wrong_value = b"wrong_value".to_vec();
6664
6665        sparse.update_leaf(path, value, &provider).unwrap();
6666
6667        // Check with wrong expected value
6668        let result = sparse.find_leaf(&path, Some(&wrong_value));
6669        assert_matches!(
6670            result,
6671            Err(LeafLookupError::ValueMismatch { path: p, expected: Some(e), actual: _a }) if p == path && e == wrong_value
6672        );
6673    }
6674
6675    #[test]
6676    fn find_leaf_not_found_empty_trie() {
6677        // Empty trie
6678        let sparse = ParallelSparseTrie::default();
6679        let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
6680
6681        // Leaf should not exist
6682        let result = sparse.find_leaf(&path, None);
6683        assert_matches!(result, Ok(LeafLookup::NonExistent));
6684    }
6685
6686    #[test]
6687    fn find_leaf_empty_trie() {
6688        let sparse = ParallelSparseTrie::default();
6689        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6690
6691        let result = sparse.find_leaf(&path, None);
6692        assert_matches!(result, Ok(LeafLookup::NonExistent));
6693    }
6694
6695    #[test]
6696    fn find_leaf_exists_no_value_check() {
6697        let provider = DefaultTrieNodeProvider;
6698        let mut sparse = ParallelSparseTrie::default();
6699        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6700        sparse.update_leaf(path, encode_account_value(0), &provider).unwrap();
6701
6702        let result = sparse.find_leaf(&path, None);
6703        assert_matches!(result, Ok(LeafLookup::Exists));
6704    }
6705
6706    #[test]
6707    fn find_leaf_exists_with_value_check_ok() {
6708        let provider = DefaultTrieNodeProvider;
6709        let mut sparse = ParallelSparseTrie::default();
6710        let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6711        let value = encode_account_value(0);
6712        sparse.update_leaf(path, value.clone(), &provider).unwrap();
6713
6714        let result = sparse.find_leaf(&path, Some(&value));
6715        assert_matches!(result, Ok(LeafLookup::Exists));
6716    }
6717
6718    #[test]
6719    fn find_leaf_exclusion_branch_divergence() {
6720        let provider = DefaultTrieNodeProvider;
6721        let mut sparse = ParallelSparseTrie::default();
6722        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); // Creates branch at 0x12
6723        let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]); // Belongs to same branch
6724        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]); // Diverges at nibble 7
6725
6726        sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
6727        sparse.update_leaf(path2, encode_account_value(1), &provider).unwrap();
6728
6729        let result = sparse.find_leaf(&search_path, None);
6730        assert_matches!(result, Ok(LeafLookup::NonExistent))
6731    }
6732
6733    #[test]
6734    fn find_leaf_exclusion_extension_divergence() {
6735        let provider = DefaultTrieNodeProvider;
6736        let mut sparse = ParallelSparseTrie::default();
6737        // This will create an extension node at root with key 0x12
6738        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
6739        // This path diverges from the extension key
6740        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]);
6741
6742        sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
6743
6744        let result = sparse.find_leaf(&search_path, None);
6745        assert_matches!(result, Ok(LeafLookup::NonExistent))
6746    }
6747
6748    #[test]
6749    fn find_leaf_exclusion_leaf_divergence() {
6750        let provider = DefaultTrieNodeProvider;
6751        let mut sparse = ParallelSparseTrie::default();
6752        let existing_leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6753        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
6754
6755        sparse.update_leaf(existing_leaf_path, encode_account_value(0), &provider).unwrap();
6756
6757        let result = sparse.find_leaf(&search_path, None);
6758        assert_matches!(result, Ok(LeafLookup::NonExistent))
6759    }
6760
6761    #[test]
6762    fn find_leaf_exclusion_path_ends_at_branch() {
6763        let provider = DefaultTrieNodeProvider;
6764        let mut sparse = ParallelSparseTrie::default();
6765        let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); // Creates branch at 0x12
6766        let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]);
6767        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2]); // Path of the branch itself
6768
6769        sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
6770        sparse.update_leaf(path2, encode_account_value(1), &provider).unwrap();
6771
6772        let result = sparse.find_leaf(&search_path, None);
6773        assert_matches!(result, Ok(LeafLookup::NonExistent));
6774    }
6775
6776    #[test]
6777    fn find_leaf_error_blinded_node_at_leaf_path() {
6778        // Scenario: The node *at* the leaf path is blinded.
6779        let blinded_hash = B256::repeat_byte(0xBB);
6780        let leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6781
6782        let sparse = new_test_trie(
6783            [
6784                (
6785                    // Ext 0x12
6786                    Nibbles::default(),
6787                    SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x1, 0x2])),
6788                ),
6789                (
6790                    // Ext 0x123
6791                    Nibbles::from_nibbles_unchecked([0x1, 0x2]),
6792                    SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x3])),
6793                ),
6794                (
6795                    // Branch at 0x123, child 4
6796                    Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3]),
6797                    SparseNode::new_branch(TrieMask::new(0b10000)),
6798                ),
6799                (
6800                    // Blinded node at 0x1234
6801                    leaf_path,
6802                    SparseNode::Hash(blinded_hash),
6803                ),
6804            ]
6805            .into_iter(),
6806        );
6807
6808        let result = sparse.find_leaf(&leaf_path, None);
6809
6810        // Should error because it hit the blinded node exactly at the leaf path
6811        assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
6812            if path == leaf_path && hash == blinded_hash
6813        );
6814    }
6815
6816    #[test]
6817    fn find_leaf_error_blinded_node() {
6818        let blinded_hash = B256::repeat_byte(0xAA);
6819        let path_to_blind = Nibbles::from_nibbles_unchecked([0x1]);
6820        let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
6821
6822        let sparse = new_test_trie(
6823            [
6824                // Root is a branch with child 0x1 (blinded) and 0x5 (revealed leaf)
6825                // So we set Bit 1 and Bit 5 in the state_mask
6826                (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b100010))),
6827                (path_to_blind, SparseNode::Hash(blinded_hash)),
6828                (
6829                    Nibbles::from_nibbles_unchecked([0x5]),
6830                    SparseNode::new_leaf(Nibbles::from_nibbles_unchecked([0x6, 0x7, 0x8])),
6831                ),
6832            ]
6833            .into_iter(),
6834        );
6835
6836        let result = sparse.find_leaf(&search_path, None);
6837
6838        // Should error because it hit the blinded node at path 0x1
6839        assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
6840            if path == path_to_blind && hash == blinded_hash
6841        );
6842    }
6843}