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