reth_trie_sparse_parallel/
trie.rs

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