1use crate::{
2 lower::LowerSparseSubtrie,
3 provider::{RevealedNode, TrieNodeProvider},
4 LeafLookup, LeafLookupError, RlpNodeStackItem, SparseNode, SparseNodeType, SparseTrie,
5 SparseTrieUpdates,
6};
7use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};
8use alloy_primitives::{
9 map::{Entry, HashMap},
10 B256, U256,
11};
12use alloy_rlp::Decodable;
13use alloy_trie::{BranchNodeCompact, TrieMask, EMPTY_ROOT_HASH};
14use core::cmp::{Ord, Ordering, PartialOrd};
15use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind, SparseTrieResult};
16use reth_trie_common::{
17 prefix_set::{PrefixSet, PrefixSetMut},
18 BranchNodeMasks, BranchNodeMasksMap, BranchNodeRef, ExtensionNodeRef, LeafNodeRef, Nibbles,
19 ProofTrieNode, RlpNode, TrieNode,
20};
21use smallvec::SmallVec;
22use tracing::{debug, instrument, trace};
23
24pub const UPPER_TRIE_MAX_DEPTH: usize = 2;
27
28pub const NUM_LOWER_SUBTRIES: usize = 16usize.pow(UPPER_TRIE_MAX_DEPTH as u32);
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
33pub struct ParallelismThresholds {
34 pub min_revealed_nodes: usize,
37 pub min_updated_nodes: usize,
41}
42
43#[derive(Clone, PartialEq, Eq, Debug)]
105pub struct ParallelSparseTrie {
106 upper_subtrie: Box<SparseSubtrie>,
108 lower_subtries: Box<[LowerSparseSubtrie; NUM_LOWER_SUBTRIES]>,
110 prefix_set: PrefixSetMut,
113 updates: Option<SparseTrieUpdates>,
115 branch_node_masks: BranchNodeMasksMap,
121 update_actions_buffers: Vec<Vec<SparseTrieUpdatesAction>>,
124 parallelism_thresholds: ParallelismThresholds,
126 subtrie_heat: SubtrieModifications,
129 #[cfg(feature = "metrics")]
131 metrics: crate::metrics::ParallelSparseTrieMetrics,
132}
133
134impl Default for ParallelSparseTrie {
135 fn default() -> Self {
136 Self {
137 upper_subtrie: Box::new(SparseSubtrie {
138 nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]),
139 ..Default::default()
140 }),
141 lower_subtries: Box::new(
142 [const { LowerSparseSubtrie::Blind(None) }; NUM_LOWER_SUBTRIES],
143 ),
144 prefix_set: PrefixSetMut::default(),
145 updates: None,
146 branch_node_masks: BranchNodeMasksMap::default(),
147 update_actions_buffers: Vec::default(),
148 parallelism_thresholds: Default::default(),
149 subtrie_heat: SubtrieModifications::default(),
150 #[cfg(feature = "metrics")]
151 metrics: Default::default(),
152 }
153 }
154}
155
156impl SparseTrie for ParallelSparseTrie {
157 fn set_root(
158 &mut self,
159 root: TrieNode,
160 masks: Option<BranchNodeMasks>,
161 retain_updates: bool,
162 ) -> SparseTrieResult<()> {
163 let path = Nibbles::default();
166 let _removed_root = self.upper_subtrie.nodes.remove(&path).expect("root node should exist");
167 debug_assert_eq!(_removed_root, SparseNode::Empty);
168
169 self.set_updates(retain_updates);
170
171 self.reveal_upper_node(Nibbles::default(), &root, masks)
172 }
173
174 fn set_updates(&mut self, retain_updates: bool) {
175 self.updates = retain_updates.then(Default::default);
176 }
177
178 fn reveal_nodes(&mut self, nodes: &mut [ProofTrieNode]) -> SparseTrieResult<()> {
179 if nodes.is_empty() {
180 return Ok(())
181 }
182
183 nodes.sort_unstable_by(
186 |ProofTrieNode { path: path_a, .. }, ProofTrieNode { path: path_b, .. }| {
187 let subtrie_type_a = SparseSubtrieType::from_path(path_a);
188 let subtrie_type_b = SparseSubtrieType::from_path(path_b);
189 subtrie_type_a.cmp(&subtrie_type_b).then_with(|| path_a.cmp(path_b))
190 },
191 );
192
193 self.branch_node_masks.reserve(nodes.len());
195 for ProofTrieNode { path, masks, .. } in nodes.iter() {
196 if let Some(branch_masks) = masks {
197 self.branch_node_masks.insert(*path, *branch_masks);
198 }
199 }
200
201 let num_upper_nodes = nodes
205 .iter()
206 .position(|n| !SparseSubtrieType::path_len_is_upper(n.path.len()))
207 .unwrap_or(nodes.len());
208 let (upper_nodes, lower_nodes) = nodes.split_at(num_upper_nodes);
209
210 self.upper_subtrie.nodes.reserve(upper_nodes.len());
213 for node in upper_nodes {
214 self.reveal_upper_node(node.path, &node.node, node.masks)?;
215 }
216
217 let reachable_subtries = self.reachable_subtries();
218
219 if !self.is_reveal_parallelism_enabled(lower_nodes.len()) {
220 for node in lower_nodes {
221 let idx = path_subtrie_index_unchecked(&node.path);
222 if !reachable_subtries.get(idx) {
223 trace!(
224 target: "trie::parallel_sparse",
225 reveal_path = ?node.path,
226 "Node's lower subtrie is not reachable, skipping",
227 );
228 continue;
229 }
230 if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
232 !Self::is_boundary_leaf_reachable(
233 &self.upper_subtrie.nodes,
234 &node.path,
235 &node.node,
236 )
237 {
238 trace!(
239 target: "trie::parallel_sparse",
240 path = ?node.path,
241 "Boundary leaf not reachable from upper subtrie, skipping",
242 );
243 continue;
244 }
245 self.lower_subtries[idx].reveal(&node.path);
246 self.subtrie_heat.mark_modified(idx);
247 self.lower_subtries[idx]
248 .as_revealed_mut()
249 .expect("just revealed")
250 .reveal_node(node.path, &node.node, node.masks)?;
251 }
252 return Ok(())
253 }
254
255 #[cfg(not(feature = "std"))]
256 unreachable!("nostd is checked by is_reveal_parallelism_enabled");
257
258 #[cfg(feature = "std")]
259 {
261 use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
262 use tracing::Span;
263
264 let parent_span = Span::current();
266
267 let upper_nodes = &self.upper_subtrie.nodes;
269
270 let node_groups: Vec<_> = lower_nodes
273 .chunk_by(|node_a, node_b| {
274 SparseSubtrieType::from_path(&node_a.path) ==
275 SparseSubtrieType::from_path(&node_b.path)
276 })
277 .collect();
278
279 let lower_subtries: Vec<_> = node_groups
283 .iter()
284 .filter_map(|nodes| {
285 let node = &nodes[0];
287 let idx =
288 SparseSubtrieType::from_path(&node.path).lower_index().unwrap_or_else(
289 || panic!("upper subtrie node {node:?} found amongst lower nodes"),
290 );
291
292 if !reachable_subtries.get(idx) {
293 trace!(
294 target: "trie::parallel_sparse",
295 nodes = ?nodes,
296 "Lower subtrie is not reachable, skipping reveal",
297 );
298 return None;
299 }
300
301 self.lower_subtries[idx].reveal(&node.path);
306 Some((idx, self.lower_subtries[idx].take_revealed().expect("just revealed")))
307 })
308 .collect();
309
310 let results: Vec<_> = lower_subtries
313 .into_par_iter()
314 .zip(node_groups.into_par_iter())
315 .map(|((subtrie_idx, mut subtrie), nodes)| {
316 let _guard = parent_span.enter();
319
320 subtrie.nodes.reserve(nodes.len());
323
324 for node in nodes {
325 if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
328 !Self::is_boundary_leaf_reachable(
329 upper_nodes,
330 &node.path,
331 &node.node,
332 )
333 {
334 trace!(
335 target: "trie::parallel_sparse",
336 path = ?node.path,
337 "Boundary leaf not reachable from upper subtrie, skipping",
338 );
339 continue;
340 }
341 let res = subtrie.reveal_node(node.path, &node.node, node.masks);
343 if res.is_err() {
344 return (subtrie_idx, subtrie, res.map(|_| ()))
345 }
346 }
347 (subtrie_idx, subtrie, Ok(()))
348 })
349 .collect();
350
351 let mut any_err = Ok(());
354 for (subtrie_idx, subtrie, res) in results {
355 self.lower_subtries[subtrie_idx] = LowerSparseSubtrie::Revealed(subtrie);
356 if res.is_err() {
357 any_err = res;
358 }
359 }
360
361 any_err
362 }
363 }
364
365 fn update_leaf<P: TrieNodeProvider>(
366 &mut self,
367 full_path: Nibbles,
368 value: Vec<u8>,
369 provider: P,
370 ) -> SparseTrieResult<()> {
371 trace!(
372 target: "trie::parallel_sparse",
373 ?full_path,
374 value_len = value.len(),
375 "Updating leaf",
376 );
377
378 if self.upper_subtrie.inner.values.contains_key(&full_path) {
380 self.prefix_set.insert(full_path);
381 self.upper_subtrie.inner.values.insert(full_path, value);
382 return Ok(());
383 }
384 if let Some(subtrie) = self.lower_subtrie_for_path(&full_path) &&
386 subtrie.inner.values.contains_key(&full_path)
387 {
388 self.prefix_set.insert(full_path);
389 self.lower_subtrie_for_path_mut(&full_path)
390 .expect("subtrie exists")
391 .inner
392 .values
393 .insert(full_path, value);
394 return Ok(());
395 }
396
397 let retain_updates = self.updates_enabled();
398
399 self.upper_subtrie.inner.values.insert(full_path, value.clone());
402
403 let mut new_nodes = Vec::new();
412 let mut next = Some(Nibbles::default());
413 let mut modified_original: Option<(Nibbles, SparseNode)> = None;
415 let mut inserted_masks: Vec<Nibbles> = Vec::new();
417
418 while let Some(current) =
423 next.filter(|next| SparseSubtrieType::path_len_is_upper(next.len()))
424 {
425 if modified_original.is_none() &&
427 let Some(node) = self.upper_subtrie.nodes.get(¤t)
428 {
429 modified_original = Some((current, node.clone()));
430 }
431
432 let step_result =
435 self.upper_subtrie.update_next_node(current, &full_path, retain_updates);
436
437 if step_result.is_err() {
438 self.upper_subtrie.inner.values.remove(&full_path);
439 return step_result.map(|_| ());
440 }
441
442 match step_result? {
443 LeafUpdateStep::Continue { next_node } => {
444 next = Some(next_node);
445 modified_original = None;
447 }
448 LeafUpdateStep::Complete { inserted_nodes, reveal_path } => {
449 new_nodes.extend(inserted_nodes);
450
451 if let Some(reveal_path) = reveal_path {
452 let subtrie = self.subtrie_for_path_mut(&reveal_path);
453 let reveal_masks = if subtrie
454 .nodes
455 .get(&reveal_path)
456 .expect("node must exist")
457 .is_hash()
458 {
459 debug!(
460 target: "trie::parallel_sparse",
461 child_path = ?reveal_path,
462 leaf_full_path = ?full_path,
463 "Extension node child not revealed in update_leaf, falling back to db",
464 );
465 let revealed_node = match provider.trie_node(&reveal_path) {
466 Ok(node) => node,
467 Err(e) => {
468 self.rollback_insert(
469 &full_path,
470 &new_nodes,
471 &inserted_masks,
472 modified_original.take(),
473 );
474 return Err(e);
475 }
476 };
477 if let Some(RevealedNode { node, tree_mask, hash_mask }) = revealed_node
478 {
479 let decoded = match TrieNode::decode(&mut &node[..]) {
480 Ok(d) => d,
481 Err(e) => {
482 self.rollback_insert(
483 &full_path,
484 &new_nodes,
485 &inserted_masks,
486 modified_original.take(),
487 );
488 return Err(e.into());
489 }
490 };
491 trace!(
492 target: "trie::parallel_sparse",
493 ?reveal_path,
494 ?decoded,
495 ?tree_mask,
496 ?hash_mask,
497 "Revealing child (from upper)",
498 );
499 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
500 if let Err(e) = subtrie.reveal_node(reveal_path, &decoded, masks) {
501 self.rollback_insert(
502 &full_path,
503 &new_nodes,
504 &inserted_masks,
505 modified_original.take(),
506 );
507 return Err(e);
508 }
509 masks
510 } else {
511 self.rollback_insert(
512 &full_path,
513 &new_nodes,
514 &inserted_masks,
515 modified_original.take(),
516 );
517 return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
518 path: reveal_path,
519 }
520 .into())
521 }
522 } else {
523 None
524 };
525
526 if let Some(_masks) = reveal_masks {
527 self.branch_node_masks.insert(reveal_path, _masks);
528 inserted_masks.push(reveal_path);
529 }
530 }
531
532 next = None;
533 }
534 LeafUpdateStep::NodeNotFound => {
535 next = None;
536 }
537 }
538 }
539
540 for node_path in &new_nodes {
542 if SparseSubtrieType::path_len_is_upper(node_path.len()) {
544 continue
545 }
546
547 let node =
548 self.upper_subtrie.nodes.remove(node_path).expect("node belongs to upper subtrie");
549
550 let leaf_value = if let SparseNode::Leaf { key, .. } = &node {
552 let mut leaf_full_path = *node_path;
553 leaf_full_path.extend(key);
554 Some((
555 leaf_full_path,
556 self.upper_subtrie
557 .inner
558 .values
559 .remove(&leaf_full_path)
560 .expect("leaf nodes have associated values entries"),
561 ))
562 } else {
563 None
564 };
565
566 let subtrie = self.subtrie_for_path_mut(node_path);
568
569 if let Some((leaf_full_path, value)) = leaf_value {
571 subtrie.inner.values.insert(leaf_full_path, value);
572 }
573
574 subtrie.nodes.insert(*node_path, node);
576 }
577
578 if let Some(next_path) = next.filter(|n| !SparseSubtrieType::path_len_is_upper(n.len())) {
580 self.upper_subtrie.inner.values.remove(&full_path);
585
586 let subtrie = self.subtrie_for_path_mut(&next_path);
591
592 if subtrie.nodes.is_empty() {
594 subtrie.nodes.insert(subtrie.path, SparseNode::Empty);
595 }
596
597 match subtrie.update_leaf(full_path, value, provider, retain_updates) {
600 Ok(Some((revealed_path, revealed_masks))) => {
601 self.branch_node_masks.insert(revealed_path, revealed_masks);
602 }
603 Ok(None) => {}
604 Err(e) => {
605 if let Some(lower) = self.lower_subtrie_for_path_mut(&full_path) {
607 lower.inner.values.remove(&full_path);
608 }
609 for mask_path in &inserted_masks {
611 self.branch_node_masks.remove(mask_path);
612 }
613 return Err(e);
614 }
615 }
616 }
617
618 self.prefix_set.insert(full_path);
620
621 Ok(())
622 }
623
624 fn remove_leaf<P: TrieNodeProvider>(
625 &mut self,
626 full_path: &Nibbles,
627 provider: P,
628 ) -> SparseTrieResult<()> {
629 trace!(
630 target: "trie::parallel_sparse",
631 ?full_path,
632 "Removing leaf",
633 );
634
635 let leaf_path;
651 let leaf_subtrie_type;
652
653 let mut branch_parent_path: Option<Nibbles> = None;
654 let mut branch_parent_node: Option<SparseNode> = None;
655
656 let mut ext_grandparent_path: Option<Nibbles> = None;
657 let mut ext_grandparent_node: Option<SparseNode> = None;
658
659 let mut curr_path = Nibbles::new(); let mut curr_subtrie_type = SparseSubtrieType::Upper;
661
662 let mut paths_to_reset_hashes = Vec::new();
664
665 loop {
666 let curr_subtrie = match curr_subtrie_type {
667 SparseSubtrieType::Upper => &mut self.upper_subtrie,
668 SparseSubtrieType::Lower(idx) => {
669 self.lower_subtries[idx].as_revealed_mut().expect("lower subtrie is revealed")
670 }
671 };
672 let curr_node = curr_subtrie.nodes.get_mut(&curr_path).unwrap();
673
674 match Self::find_next_to_leaf(&curr_path, curr_node, full_path) {
675 FindNextToLeafOutcome::NotFound => return Ok(()), FindNextToLeafOutcome::BlindedNode(hash) => {
677 return Err(SparseTrieErrorKind::BlindedNode { path: curr_path, hash }.into())
678 }
679 FindNextToLeafOutcome::Found => {
680 leaf_path = curr_path;
682 leaf_subtrie_type = curr_subtrie_type;
683 break;
684 }
685 FindNextToLeafOutcome::ContinueFrom(next_path) => {
686 match curr_node {
689 SparseNode::Branch { hash, .. } => {
690 if hash.is_some() {
691 paths_to_reset_hashes
692 .push((SparseSubtrieType::from_path(&curr_path), curr_path));
693 }
694
695 match (&branch_parent_path, &ext_grandparent_path) {
698 (Some(branch), Some(ext)) if branch.len() > ext.len() => {
699 ext_grandparent_path = None;
700 ext_grandparent_node = None;
701 }
702 _ => (),
703 };
704 branch_parent_path = Some(curr_path);
705 branch_parent_node = Some(curr_node.clone());
706 }
707 SparseNode::Extension { hash, .. } => {
708 if hash.is_some() {
709 paths_to_reset_hashes
710 .push((SparseSubtrieType::from_path(&curr_path), curr_path));
711 }
712
713 ext_grandparent_path = Some(curr_path);
717 ext_grandparent_node = Some(curr_node.clone());
718 }
719 SparseNode::Empty | SparseNode::Hash(_) | SparseNode::Leaf { .. } => {
720 unreachable!(
721 "find_next_to_leaf only continues to a branch or extension"
722 )
723 }
724 }
725
726 curr_path = next_path;
727
728 let next_subtrie_type = SparseSubtrieType::from_path(&curr_path);
730 if matches!(curr_subtrie_type, SparseSubtrieType::Upper) &&
731 matches!(next_subtrie_type, SparseSubtrieType::Lower(_))
732 {
733 curr_subtrie_type = next_subtrie_type;
734 }
735 }
736 };
737 }
738
739 if let (Some(branch_path), Some(SparseNode::Branch { state_mask, .. })) =
742 (&branch_parent_path, &branch_parent_node)
743 {
744 let mut check_mask = *state_mask;
745 let child_nibble = leaf_path.get_unchecked(branch_path.len());
746 check_mask.unset_bit(child_nibble);
747
748 if check_mask.count_bits() == 1 {
749 let remaining_child_path = {
751 let mut p = *branch_path;
752 p.push_unchecked(
753 check_mask.first_set_bit_index().expect("state mask is not empty"),
754 );
755 p
756 };
757
758 self.pre_validate_reveal_chain(&remaining_child_path, &provider)?;
763 }
764 }
765
766 self.prefix_set.insert(*full_path);
769 let leaf_subtrie = match leaf_subtrie_type {
770 SparseSubtrieType::Upper => &mut self.upper_subtrie,
771 SparseSubtrieType::Lower(idx) => {
772 self.lower_subtries[idx].as_revealed_mut().expect("lower subtrie is revealed")
773 }
774 };
775 leaf_subtrie.inner.values.remove(full_path);
776 for (subtrie_type, path) in paths_to_reset_hashes {
777 let node = match subtrie_type {
778 SparseSubtrieType::Upper => self.upper_subtrie.nodes.get_mut(&path),
779 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx]
780 .as_revealed_mut()
781 .expect("lower subtrie is revealed")
782 .nodes
783 .get_mut(&path),
784 }
785 .expect("node exists");
786
787 match node {
788 SparseNode::Extension { hash, .. } | SparseNode::Branch { hash, .. } => {
789 *hash = None
790 }
791 SparseNode::Empty | SparseNode::Hash(_) | SparseNode::Leaf { .. } => {
792 unreachable!("only branch and extension node hashes can be reset")
793 }
794 }
795 }
796 self.remove_node(&leaf_path);
797
798 if leaf_path.is_empty() {
801 self.upper_subtrie.nodes.insert(leaf_path, SparseNode::Empty);
802 return Ok(())
803 }
804
805 if let (Some(branch_path), &Some(SparseNode::Branch { mut state_mask, .. })) =
808 (&branch_parent_path, &branch_parent_node)
809 {
810 let child_nibble = leaf_path.get_unchecked(branch_path.len());
811 state_mask.unset_bit(child_nibble);
812
813 let new_branch_node = if state_mask.count_bits() == 1 {
814 let remaining_child_path = {
817 let mut p = *branch_path;
818 p.push_unchecked(
819 state_mask.first_set_bit_index().expect("state mask is not empty"),
820 );
821 p
822 };
823
824 trace!(
825 target: "trie::parallel_sparse",
826 ?leaf_path,
827 ?branch_path,
828 ?remaining_child_path,
829 "Branch node has only one child",
830 );
831
832 let remaining_child_node = self.reveal_remaining_child_on_leaf_removal(
835 provider,
836 full_path,
837 &remaining_child_path,
838 true, )?;
840
841 let (new_branch_node, remove_child) = Self::branch_changes_on_leaf_removal(
842 branch_path,
843 &remaining_child_path,
844 &remaining_child_node,
845 );
846
847 if remove_child {
848 self.move_value_on_leaf_removal(
849 branch_path,
850 &new_branch_node,
851 &remaining_child_path,
852 );
853 self.remove_node(&remaining_child_path);
854 }
855
856 if let Some(updates) = self.updates.as_mut() {
857 updates.updated_nodes.remove(branch_path);
858 updates.removed_nodes.insert(*branch_path);
859 }
860
861 new_branch_node
862 } else {
863 SparseNode::new_branch(state_mask)
866 };
867
868 let branch_subtrie = self.subtrie_for_path_mut(branch_path);
869 branch_subtrie.nodes.insert(*branch_path, new_branch_node.clone());
870 branch_parent_node = Some(new_branch_node);
871 };
872
873 if let (Some(ext_path), Some(SparseNode::Extension { key: shortkey, .. })) =
877 (ext_grandparent_path, &ext_grandparent_node)
878 {
879 let ext_subtrie = self.subtrie_for_path_mut(&ext_path);
880 let branch_path = branch_parent_path.as_ref().unwrap();
881
882 if let Some(new_ext_node) = Self::extension_changes_on_leaf_removal(
883 &ext_path,
884 shortkey,
885 branch_path,
886 branch_parent_node.as_ref().unwrap(),
887 ) {
888 ext_subtrie.nodes.insert(ext_path, new_ext_node.clone());
889 self.move_value_on_leaf_removal(&ext_path, &new_ext_node, branch_path);
890 self.remove_node(branch_path);
891 }
892 }
893
894 Ok(())
895 }
896
897 #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
898 fn root(&mut self) -> B256 {
899 trace!(target: "trie::parallel_sparse", "Calculating trie root hash");
900
901 if self.prefix_set.is_empty() &&
902 let Some(hash) =
903 self.upper_subtrie.nodes.get(&Nibbles::default()).and_then(|node| node.hash())
904 {
905 return hash;
906 }
907
908 self.update_subtrie_hashes();
910
911 let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
914 let root_rlp = self.update_upper_subtrie_hashes(&mut prefix_set);
915
916 root_rlp.as_hash().unwrap_or(EMPTY_ROOT_HASH)
918 }
919
920 fn is_root_cached(&self) -> bool {
921 self.prefix_set.is_empty() &&
922 self.upper_subtrie
923 .nodes
924 .get(&Nibbles::default())
925 .is_some_and(|node| node.hash().is_some())
926 }
927
928 #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
929 fn update_subtrie_hashes(&mut self) {
930 trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
931
932 let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
934 let num_changed_keys = prefix_set.len();
935 let (mut changed_subtries, unchanged_prefix_set) =
936 self.take_changed_lower_subtries(&mut prefix_set);
937
938 #[cfg(feature = "metrics")]
940 self.metrics.subtries_updated.record(changed_subtries.len() as f64);
941
942 self.prefix_set = unchanged_prefix_set;
944
945 if !self.is_update_parallelism_enabled(num_changed_keys) {
947 for changed_subtrie in &mut changed_subtries {
948 changed_subtrie.subtrie.update_hashes(
949 &mut changed_subtrie.prefix_set,
950 &mut changed_subtrie.update_actions_buf,
951 &self.branch_node_masks,
952 );
953 }
954
955 self.insert_changed_subtries(changed_subtries);
956 return
957 }
958
959 #[cfg(not(feature = "std"))]
960 unreachable!("nostd is checked by is_update_parallelism_enabled");
961
962 #[cfg(feature = "std")]
963 {
965 use rayon::prelude::*;
966
967 changed_subtries.par_iter_mut().for_each(|changed_subtrie| {
968 #[cfg(feature = "metrics")]
969 let start = std::time::Instant::now();
970 changed_subtrie.subtrie.update_hashes(
971 &mut changed_subtrie.prefix_set,
972 &mut changed_subtrie.update_actions_buf,
973 &self.branch_node_masks,
974 );
975 #[cfg(feature = "metrics")]
976 self.metrics.subtrie_hash_update_latency.record(start.elapsed());
977 });
978
979 self.insert_changed_subtries(changed_subtries);
980 }
981 }
982
983 fn get_leaf_value(&self, full_path: &Nibbles) -> Option<&Vec<u8>> {
984 if let Some(subtrie) = self.subtrie_for_path(full_path) &&
989 !subtrie.is_empty()
990 {
991 return subtrie.inner.values.get(full_path);
992 }
993
994 self.upper_subtrie.inner.values.get(full_path)
995 }
996
997 fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates> {
998 self.updates.as_ref().map_or(Cow::Owned(SparseTrieUpdates::default()), Cow::Borrowed)
999 }
1000
1001 fn take_updates(&mut self) -> SparseTrieUpdates {
1002 match self.updates.take() {
1003 Some(updates) => {
1004 for (path, node) in &updates.updated_nodes {
1008 self.branch_node_masks.insert(
1009 *path,
1010 BranchNodeMasks { tree_mask: node.tree_mask, hash_mask: node.hash_mask },
1011 );
1012 }
1013 for path in &updates.removed_nodes {
1014 self.branch_node_masks.remove(path);
1015 }
1016
1017 self.updates = Some(SparseTrieUpdates::with_capacity(
1019 updates.updated_nodes.len(),
1020 updates.removed_nodes.len(),
1021 ));
1022 updates
1023 }
1024 None => SparseTrieUpdates::default(),
1025 }
1026 }
1027
1028 fn wipe(&mut self) {
1029 self.upper_subtrie.wipe();
1030 for trie in &mut *self.lower_subtries {
1031 trie.wipe();
1032 }
1033 self.prefix_set = PrefixSetMut::all();
1034 self.updates = self.updates.is_some().then(SparseTrieUpdates::wiped);
1035 self.subtrie_heat.clear();
1036 }
1037
1038 fn clear(&mut self) {
1039 self.upper_subtrie.clear();
1040 self.upper_subtrie.nodes.insert(Nibbles::default(), SparseNode::Empty);
1041 for subtrie in &mut *self.lower_subtries {
1042 subtrie.clear();
1043 }
1044 self.prefix_set.clear();
1045 self.updates = None;
1046 self.branch_node_masks.clear();
1047 self.subtrie_heat.clear();
1048 }
1051
1052 fn find_leaf(
1053 &self,
1054 full_path: &Nibbles,
1055 expected_value: Option<&Vec<u8>>,
1056 ) -> Result<LeafLookup, LeafLookupError> {
1057 if let Some(actual_value) = core::iter::once(self.upper_subtrie.as_ref())
1063 .chain(self.lower_subtrie_for_path(full_path))
1064 .filter_map(|subtrie| subtrie.inner.values.get(full_path))
1065 .next()
1066 {
1067 return expected_value
1069 .is_none_or(|v| v == actual_value)
1070 .then_some(LeafLookup::Exists)
1071 .ok_or_else(|| LeafLookupError::ValueMismatch {
1072 path: *full_path,
1073 expected: expected_value.cloned(),
1074 actual: actual_value.clone(),
1075 })
1076 }
1077
1078 let mut curr_path = Nibbles::new(); let mut curr_subtrie = self.upper_subtrie.as_ref();
1086 let mut curr_subtrie_is_upper = true;
1087
1088 loop {
1089 let curr_node = curr_subtrie.nodes.get(&curr_path).unwrap();
1090
1091 match Self::find_next_to_leaf(&curr_path, curr_node, full_path) {
1092 FindNextToLeafOutcome::NotFound => return Ok(LeafLookup::NonExistent),
1093 FindNextToLeafOutcome::BlindedNode(hash) => {
1094 return Err(LeafLookupError::BlindedNode { path: curr_path, hash });
1096 }
1097 FindNextToLeafOutcome::Found => {
1098 panic!("target leaf {full_path:?} found at path {curr_path:?}, even though value wasn't in values hashmap");
1099 }
1100 FindNextToLeafOutcome::ContinueFrom(next_path) => {
1101 curr_path = next_path;
1102 if curr_subtrie_is_upper &&
1105 let Some(lower_subtrie) = self.lower_subtrie_for_path(&curr_path)
1106 {
1107 curr_subtrie = lower_subtrie;
1108 curr_subtrie_is_upper = false;
1109 }
1110 }
1111 }
1112 }
1113 }
1114
1115 fn shrink_nodes_to(&mut self, size: usize) {
1116 let total_subtries = 1 + NUM_LOWER_SUBTRIES;
1120 let size_per_subtrie = size / total_subtries;
1121
1122 self.upper_subtrie.shrink_nodes_to(size_per_subtrie);
1124
1125 for subtrie in &mut *self.lower_subtries {
1127 subtrie.shrink_nodes_to(size_per_subtrie);
1128 }
1129
1130 self.branch_node_masks.shrink_to(size);
1132 }
1133
1134 fn shrink_values_to(&mut self, size: usize) {
1135 let total_subtries = 1 + NUM_LOWER_SUBTRIES;
1139 let size_per_subtrie = size / total_subtries;
1140
1141 self.upper_subtrie.shrink_values_to(size_per_subtrie);
1143
1144 for subtrie in &mut *self.lower_subtries {
1146 subtrie.shrink_values_to(size_per_subtrie);
1147 }
1148 }
1149
1150 fn size_hint(&self) -> usize {
1152 let upper_count = self.upper_subtrie.nodes.len();
1153 let lower_count: usize = self
1154 .lower_subtries
1155 .iter()
1156 .filter_map(|s| s.as_revealed_ref())
1157 .map(|s| s.nodes.len())
1158 .sum();
1159 upper_count + lower_count
1160 }
1161
1162 fn prune(&mut self, max_depth: usize) -> usize {
1163 self.subtrie_heat.decay_and_reset();
1165
1166 let mut effective_pruned_roots = Vec::<(Nibbles, B256)>::new();
1170 let mut stack: SmallVec<[(Nibbles, usize); 32]> = SmallVec::new();
1171 stack.push((Nibbles::default(), 0));
1172
1173 while let Some((path, depth)) = stack.pop() {
1175 if depth > max_depth &&
1179 let SparseSubtrieType::Lower(idx) = SparseSubtrieType::from_path(&path) &&
1180 self.subtrie_heat.is_hot(idx)
1181 {
1182 continue;
1183 }
1184
1185 let children: SmallVec<[Nibbles; 16]> = {
1187 let Some(subtrie) = self.subtrie_for_path(&path) else { continue };
1188 let Some(node) = subtrie.nodes.get(&path) else { continue };
1189
1190 match node {
1191 SparseNode::Empty | SparseNode::Hash(_) | SparseNode::Leaf { .. } => {
1192 SmallVec::new()
1193 }
1194 SparseNode::Extension { key, .. } => {
1195 let mut child = path;
1196 child.extend(key);
1197 SmallVec::from_slice(&[child])
1198 }
1199 SparseNode::Branch { state_mask, .. } => {
1200 let mut children = SmallVec::new();
1201 let mut mask = state_mask.get();
1202 while mask != 0 {
1203 let nibble = mask.trailing_zeros() as u8;
1204 mask &= mask - 1;
1205 let mut child = path;
1206 child.push_unchecked(nibble);
1207 children.push(child);
1208 }
1209 children
1210 }
1211 }
1212 };
1213
1214 for child in children {
1216 if depth == max_depth {
1217 let hash = self
1219 .subtrie_for_path(&child)
1220 .and_then(|s| s.nodes.get(&child))
1221 .filter(|n| !n.is_hash())
1222 .and_then(|n| n.hash());
1223
1224 if let Some(hash) = hash {
1225 if let Some(subtrie) = self.subtrie_for_path_mut_untracked(&child) {
1227 subtrie.nodes.insert(child, SparseNode::Hash(hash));
1228 effective_pruned_roots.push((child, hash));
1229 }
1230 }
1231 } else {
1232 stack.push((child, depth + 1));
1233 }
1234 }
1235 }
1236
1237 if effective_pruned_roots.is_empty() {
1238 return 0;
1239 }
1240
1241 let nodes_converted = effective_pruned_roots.len();
1242
1243 effective_pruned_roots.sort_unstable_by(|(path_a, _), (path_b, _)| {
1245 let subtrie_type_a = SparseSubtrieType::from_path(path_a);
1246 let subtrie_type_b = SparseSubtrieType::from_path(path_b);
1247 subtrie_type_a.cmp(&subtrie_type_b).then(path_a.cmp(path_b))
1248 });
1249
1250 let num_upper_roots = effective_pruned_roots
1252 .iter()
1253 .position(|(p, _)| !SparseSubtrieType::path_len_is_upper(p.len()))
1254 .unwrap_or(effective_pruned_roots.len());
1255
1256 let roots_upper = &effective_pruned_roots[..num_upper_roots];
1257 let roots_lower = &effective_pruned_roots[num_upper_roots..];
1258
1259 debug_assert!(
1260 {
1261 let mut all_roots: Vec<_> = effective_pruned_roots.iter().map(|(p, _)| p).collect();
1262 all_roots.sort_unstable();
1263 all_roots.windows(2).all(|w| !w[1].starts_with(w[0]))
1264 },
1265 "prune roots must be prefix-free"
1266 );
1267
1268 if !roots_upper.is_empty() {
1271 for subtrie in &mut *self.lower_subtries {
1272 let should_clear = subtrie.as_revealed_ref().is_some_and(|s| {
1273 let search_idx = roots_upper.partition_point(|(root, _)| root <= &s.path);
1274 search_idx > 0 && s.path.starts_with(&roots_upper[search_idx - 1].0)
1275 });
1276 if should_clear {
1277 subtrie.clear();
1278 }
1279 }
1280 }
1281
1282 self.upper_subtrie.nodes.retain(|p, _| !is_strict_descendant_in(roots_upper, p));
1284 self.upper_subtrie.inner.values.retain(|p, _| {
1285 !starts_with_pruned_in(roots_upper, p) && !starts_with_pruned_in(roots_lower, p)
1286 });
1287
1288 for roots_group in roots_lower.chunk_by(|(path_a, _), (path_b, _)| {
1290 SparseSubtrieType::from_path(path_a) == SparseSubtrieType::from_path(path_b)
1291 }) {
1292 let subtrie_idx = path_subtrie_index_unchecked(&roots_group[0].0);
1293
1294 let Some(subtrie) = self.lower_subtries[subtrie_idx].as_revealed_mut() else {
1296 continue;
1297 };
1298
1299 subtrie.nodes.retain(|p, _| !is_strict_descendant_in(roots_group, p));
1301 subtrie.inner.values.retain(|p, _| !starts_with_pruned_in(roots_group, p));
1302 }
1303
1304 self.branch_node_masks.retain(|p, _| {
1306 if SparseSubtrieType::path_len_is_upper(p.len()) {
1307 !starts_with_pruned_in(roots_upper, p)
1308 } else {
1309 !starts_with_pruned_in(roots_lower, p) && !starts_with_pruned_in(roots_upper, p)
1310 }
1311 });
1312
1313 nodes_converted
1314 }
1315
1316 fn update_leaves(
1317 &mut self,
1318 updates: &mut alloy_primitives::map::B256Map<crate::LeafUpdate>,
1319 mut proof_required_fn: impl FnMut(B256, u8),
1320 ) -> SparseTrieResult<()> {
1321 use crate::{provider::NoRevealProvider, LeafUpdate};
1322
1323 let keys: Vec<B256> = updates.keys().copied().collect();
1326
1327 for key in keys {
1328 let full_path = Nibbles::unpack(key);
1329 let update = updates.remove(&key).unwrap();
1331
1332 match update {
1333 LeafUpdate::Changed(value) => {
1334 if value.is_empty() {
1335 match self.remove_leaf(&full_path, NoRevealProvider) {
1338 Ok(()) => {}
1339 Err(e) => {
1340 if let Some(path) = Self::get_retriable_path(&e) {
1341 let (target_key, min_len) =
1342 Self::proof_target_for_path(key, &full_path, &path);
1343 proof_required_fn(target_key, min_len);
1344 updates.insert(key, LeafUpdate::Changed(value));
1345 } else {
1346 return Err(e);
1347 }
1348 }
1349 }
1350 } else {
1351 if let Err(e) = self.update_leaf(full_path, value.clone(), NoRevealProvider)
1353 {
1354 if let Some(path) = Self::get_retriable_path(&e) {
1355 let (target_key, min_len) =
1356 Self::proof_target_for_path(key, &full_path, &path);
1357 proof_required_fn(target_key, min_len);
1358 updates.insert(key, LeafUpdate::Changed(value));
1359 } else {
1360 return Err(e);
1361 }
1362 }
1363 }
1364 }
1365 LeafUpdate::Touched => {
1366 match self.find_leaf(&full_path, None) {
1368 Err(LeafLookupError::BlindedNode { path, .. }) => {
1369 let (target_key, min_len) =
1370 Self::proof_target_for_path(key, &full_path, &path);
1371 proof_required_fn(target_key, min_len);
1372 updates.insert(key, LeafUpdate::Touched);
1373 }
1374 Ok(_) | Err(LeafLookupError::ValueMismatch { .. }) => {}
1376 }
1377 }
1378 }
1379 }
1380
1381 Ok(())
1382 }
1383}
1384
1385impl ParallelSparseTrie {
1386 pub const fn with_parallelism_thresholds(mut self, thresholds: ParallelismThresholds) -> Self {
1388 self.parallelism_thresholds = thresholds;
1389 self
1390 }
1391
1392 const fn updates_enabled(&self) -> bool {
1394 self.updates.is_some()
1395 }
1396
1397 const fn is_reveal_parallelism_enabled(&self, num_nodes: usize) -> bool {
1400 #[cfg(not(feature = "std"))]
1401 {
1402 let _ = num_nodes;
1403 return false;
1404 }
1405
1406 #[cfg(feature = "std")]
1407 {
1408 num_nodes >= self.parallelism_thresholds.min_revealed_nodes
1409 }
1410 }
1411
1412 const fn is_update_parallelism_enabled(&self, num_changed_keys: usize) -> bool {
1415 #[cfg(not(feature = "std"))]
1416 {
1417 let _ = num_changed_keys;
1418 return false;
1419 }
1420
1421 #[cfg(feature = "std")]
1422 {
1423 num_changed_keys >= self.parallelism_thresholds.min_updated_nodes
1424 }
1425 }
1426
1427 const fn get_retriable_path(e: &SparseTrieError) -> Option<Nibbles> {
1434 match e.kind() {
1435 SparseTrieErrorKind::BlindedNode { path, .. } |
1436 SparseTrieErrorKind::NodeNotFoundInProvider { path } => Some(*path),
1437 _ => None,
1438 }
1439 }
1440
1441 fn nibbles_to_padded_b256(path: &Nibbles) -> B256 {
1443 let mut bytes = [0u8; 32];
1444 path.pack_to(&mut bytes);
1445 B256::from(bytes)
1446 }
1447
1448 fn proof_target_for_path(full_key: B256, full_path: &Nibbles, path: &Nibbles) -> (B256, u8) {
1454 let min_len = (path.len() as u8).min(64);
1455 let target_key =
1456 if full_path.starts_with(path) { full_key } else { Self::nibbles_to_padded_b256(path) };
1457 (target_key, min_len)
1458 }
1459
1460 fn rollback_insert(
1465 &mut self,
1466 full_path: &Nibbles,
1467 inserted_nodes: &[Nibbles],
1468 inserted_masks: &[Nibbles],
1469 modified_original: Option<(Nibbles, SparseNode)>,
1470 ) {
1471 self.upper_subtrie.inner.values.remove(full_path);
1472 for node_path in inserted_nodes {
1473 if self.upper_subtrie.nodes.remove(node_path).is_none() {
1475 if let Some(subtrie) = self.lower_subtrie_for_path_mut(node_path) {
1477 subtrie.nodes.remove(node_path);
1478 }
1479 }
1480 }
1481 for mask_path in inserted_masks {
1483 self.branch_node_masks.remove(mask_path);
1484 }
1485 if let Some((path, original_node)) = modified_original {
1487 self.upper_subtrie.nodes.insert(path, original_node);
1488 }
1489 }
1490
1491 pub fn from_root(
1506 root: TrieNode,
1507 masks: Option<BranchNodeMasks>,
1508 retain_updates: bool,
1509 ) -> SparseTrieResult<Self> {
1510 Self::default().with_root(root, masks, retain_updates)
1511 }
1512
1513 fn lower_subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
1517 match SparseSubtrieType::from_path(path) {
1518 SparseSubtrieType::Upper => None,
1519 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx].as_revealed_ref(),
1520 }
1521 }
1522
1523 fn lower_subtrie_for_path_mut(&mut self, path: &Nibbles) -> Option<&mut SparseSubtrie> {
1530 match SparseSubtrieType::from_path(path) {
1531 SparseSubtrieType::Upper => None,
1532 SparseSubtrieType::Lower(idx) => {
1533 self.lower_subtries[idx].reveal(path);
1534 self.subtrie_heat.mark_modified(idx);
1535 Some(self.lower_subtries[idx].as_revealed_mut().expect("just revealed"))
1536 }
1537 }
1538 }
1539
1540 fn subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
1545 if SparseSubtrieType::path_len_is_upper(path.len()) {
1546 Some(&self.upper_subtrie)
1547 } else {
1548 self.lower_subtrie_for_path(path)
1549 }
1550 }
1551
1552 fn subtrie_for_path_mut(&mut self, path: &Nibbles) -> &mut SparseSubtrie {
1559 if SparseSubtrieType::path_len_is_upper(path.len()) {
1562 &mut self.upper_subtrie
1563 } else {
1564 self.lower_subtrie_for_path_mut(path).unwrap()
1565 }
1566 }
1567
1568 fn subtrie_for_path_mut_untracked(&mut self, path: &Nibbles) -> Option<&mut SparseSubtrie> {
1571 if SparseSubtrieType::path_len_is_upper(path.len()) {
1572 Some(&mut self.upper_subtrie)
1573 } else {
1574 match SparseSubtrieType::from_path(path) {
1575 SparseSubtrieType::Upper => None,
1576 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx].as_revealed_mut(),
1577 }
1578 }
1579 }
1580
1581 fn find_next_to_leaf(
1589 from_path: &Nibbles,
1590 from_node: &SparseNode,
1591 leaf_full_path: &Nibbles,
1592 ) -> FindNextToLeafOutcome {
1593 debug_assert!(leaf_full_path.len() >= from_path.len());
1594 debug_assert!(leaf_full_path.starts_with(from_path));
1595
1596 match from_node {
1597 SparseNode::Empty => FindNextToLeafOutcome::NotFound,
1600 SparseNode::Hash(hash) => FindNextToLeafOutcome::BlindedNode(*hash),
1601 SparseNode::Leaf { key, .. } => {
1602 let mut found_full_path = *from_path;
1603 found_full_path.extend(key);
1604
1605 if &found_full_path == leaf_full_path {
1606 return FindNextToLeafOutcome::Found
1607 }
1608 FindNextToLeafOutcome::NotFound
1609 }
1610 SparseNode::Extension { key, .. } => {
1611 if leaf_full_path.len() == from_path.len() {
1612 return FindNextToLeafOutcome::NotFound
1613 }
1614
1615 let mut child_path = *from_path;
1616 child_path.extend(key);
1617
1618 if !leaf_full_path.starts_with(&child_path) {
1619 return FindNextToLeafOutcome::NotFound
1620 }
1621 FindNextToLeafOutcome::ContinueFrom(child_path)
1622 }
1623 SparseNode::Branch { state_mask, .. } => {
1624 if leaf_full_path.len() == from_path.len() {
1625 return FindNextToLeafOutcome::NotFound
1626 }
1627
1628 let nibble = leaf_full_path.get_unchecked(from_path.len());
1629 if !state_mask.is_bit_set(nibble) {
1630 return FindNextToLeafOutcome::NotFound
1631 }
1632
1633 let mut child_path = *from_path;
1634 child_path.push_unchecked(nibble);
1635
1636 FindNextToLeafOutcome::ContinueFrom(child_path)
1637 }
1638 }
1639 }
1640
1641 fn move_value_on_leaf_removal(
1646 &mut self,
1647 parent_path: &Nibbles,
1648 new_parent_node: &SparseNode,
1649 prev_child_path: &Nibbles,
1650 ) {
1651 if SparseSubtrieType::from_path(parent_path).lower_index().is_some() {
1654 return;
1655 }
1656
1657 if let SparseNode::Leaf { key, .. } = new_parent_node {
1658 let Some(prev_child_subtrie) = self.lower_subtrie_for_path_mut(prev_child_path) else {
1659 return;
1660 };
1661
1662 let mut leaf_full_path = *parent_path;
1663 leaf_full_path.extend(key);
1664
1665 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");
1666 self.upper_subtrie.inner.values.insert(leaf_full_path, val);
1667 }
1668 }
1669
1670 fn remove_node(&mut self, path: &Nibbles) {
1682 let subtrie = self.subtrie_for_path_mut(path);
1683 let node = subtrie.nodes.remove(path);
1684
1685 let Some(idx) = SparseSubtrieType::from_path(path).lower_index() else {
1686 return;
1689 };
1690
1691 match node {
1692 Some(SparseNode::Leaf { .. }) => {
1693 if subtrie.nodes.is_empty() {
1696 self.lower_subtries[idx].clear();
1697 }
1698 }
1699 Some(SparseNode::Extension { key, .. }) => {
1700 if &subtrie.path == path {
1704 subtrie.path.extend(&key);
1705 }
1706 }
1707 _ => panic!("Expected to remove a leaf or extension, but removed {node:?}"),
1708 }
1709 }
1710
1711 fn branch_changes_on_leaf_removal(
1720 parent_path: &Nibbles,
1721 remaining_child_path: &Nibbles,
1722 remaining_child_node: &SparseNode,
1723 ) -> (SparseNode, bool) {
1724 debug_assert!(remaining_child_path.len() > parent_path.len());
1725 debug_assert!(remaining_child_path.starts_with(parent_path));
1726
1727 let remaining_child_nibble = remaining_child_path.get_unchecked(parent_path.len());
1728
1729 match remaining_child_node {
1732 SparseNode::Empty | SparseNode::Hash(_) => {
1733 panic!("remaining child must have been revealed already")
1734 }
1735 SparseNode::Leaf { key, .. } => {
1739 let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1740 new_key.extend(key);
1741 (SparseNode::new_leaf(new_key), true)
1742 }
1743 SparseNode::Extension { key, .. } => {
1747 let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1748 new_key.extend(key);
1749 (SparseNode::new_ext(new_key), true)
1750 }
1751 SparseNode::Branch { .. } => (
1754 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([remaining_child_nibble])),
1755 false,
1756 ),
1757 }
1758 }
1759
1760 fn extension_changes_on_leaf_removal(
1769 parent_path: &Nibbles,
1770 parent_key: &Nibbles,
1771 child_path: &Nibbles,
1772 child: &SparseNode,
1773 ) -> Option<SparseNode> {
1774 debug_assert!(child_path.len() > parent_path.len());
1775 debug_assert!(child_path.starts_with(parent_path));
1776
1777 match child {
1780 SparseNode::Empty | SparseNode::Hash(_) => {
1781 panic!("child must be revealed")
1782 }
1783 SparseNode::Leaf { key, .. } => {
1789 let mut new_key = *parent_key;
1790 new_key.extend(key);
1791 Some(SparseNode::new_leaf(new_key))
1792 }
1793 SparseNode::Extension { key, .. } => {
1796 let mut new_key = *parent_key;
1797 new_key.extend(key);
1798 Some(SparseNode::new_ext(new_key))
1799 }
1800 SparseNode::Branch { .. } => None,
1802 }
1803 }
1804
1805 fn pre_validate_reveal_chain<P: TrieNodeProvider>(
1812 &self,
1813 path: &Nibbles,
1814 provider: &P,
1815 ) -> SparseTrieResult<()> {
1816 let subtrie = match self.subtrie_for_path(path) {
1818 Some(s) => s,
1819 None => return Ok(()),
1820 };
1821
1822 match subtrie.nodes.get(path) {
1823 Some(SparseNode::Hash(hash)) => match provider.trie_node(path)? {
1825 Some(RevealedNode { node, .. }) => {
1826 let decoded = TrieNode::decode(&mut &node[..])?;
1827 if let TrieNode::Extension(ext) = decoded {
1829 let mut grandchild_path = *path;
1830 grandchild_path.extend(&ext.key);
1831 return self.pre_validate_reveal_chain(&grandchild_path, provider);
1832 }
1833 Ok(())
1834 }
1835 None => Err(SparseTrieErrorKind::BlindedNode { path: *path, hash: *hash }.into()),
1837 },
1838 Some(SparseNode::Extension { key, .. }) => {
1840 let mut child_path = *path;
1841 child_path.extend(key);
1842 self.pre_validate_reveal_chain(&child_path, provider)
1843 }
1844 _ => Ok(()),
1846 }
1847 }
1848
1849 fn reveal_remaining_child_on_leaf_removal<P: TrieNodeProvider>(
1859 &mut self,
1860 provider: P,
1861 full_path: &Nibbles, remaining_child_path: &Nibbles,
1863 recurse_into_extension: bool,
1864 ) -> SparseTrieResult<SparseNode> {
1865 let remaining_child_subtrie = self.subtrie_for_path_mut(remaining_child_path);
1866
1867 let (remaining_child_node, remaining_child_masks) = match remaining_child_subtrie
1868 .nodes
1869 .get(remaining_child_path)
1870 .unwrap()
1871 {
1872 SparseNode::Hash(_) => {
1873 debug!(
1874 target: "trie::parallel_sparse",
1875 child_path = ?remaining_child_path,
1876 leaf_full_path = ?full_path,
1877 "Node child not revealed in remove_leaf, falling back to db",
1878 );
1879 if let Some(RevealedNode { node, tree_mask, hash_mask }) =
1880 provider.trie_node(remaining_child_path)?
1881 {
1882 let decoded = TrieNode::decode(&mut &node[..])?;
1883 trace!(
1884 target: "trie::parallel_sparse",
1885 ?remaining_child_path,
1886 ?decoded,
1887 ?tree_mask,
1888 ?hash_mask,
1889 "Revealing remaining blinded branch child"
1890 );
1891 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
1892 remaining_child_subtrie.reveal_node(*remaining_child_path, &decoded, masks)?;
1893 (
1894 remaining_child_subtrie.nodes.get(remaining_child_path).unwrap().clone(),
1895 masks,
1896 )
1897 } else {
1898 return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
1899 path: *remaining_child_path,
1900 }
1901 .into())
1902 }
1903 }
1904 node => (node.clone(), None),
1907 };
1908
1909 if let Some(masks) = remaining_child_masks {
1910 self.branch_node_masks.insert(*remaining_child_path, masks);
1911 }
1912
1913 if let SparseNode::Extension { key, .. } = &remaining_child_node &&
1918 recurse_into_extension
1919 {
1920 let mut remaining_grandchild_path = *remaining_child_path;
1921 remaining_grandchild_path.extend(key);
1922
1923 trace!(
1924 target: "trie::parallel_sparse",
1925 remaining_grandchild_path = ?remaining_grandchild_path,
1926 child_path = ?remaining_child_path,
1927 leaf_full_path = ?full_path,
1928 "Revealing child of extension node, which is the last remaining child of the branch"
1929 );
1930
1931 self.reveal_remaining_child_on_leaf_removal(
1932 provider,
1933 full_path,
1934 &remaining_grandchild_path,
1935 false, )?;
1937 }
1938
1939 Ok(remaining_child_node)
1940 }
1941
1942 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
1945 fn apply_subtrie_update_actions(
1946 &mut self,
1947 update_actions: impl Iterator<Item = SparseTrieUpdatesAction>,
1948 ) {
1949 if let Some(updates) = self.updates.as_mut() {
1950 for action in update_actions {
1951 match action {
1952 SparseTrieUpdatesAction::InsertRemoved(path) => {
1953 updates.updated_nodes.remove(&path);
1954 updates.removed_nodes.insert(path);
1955 }
1956 SparseTrieUpdatesAction::RemoveUpdated(path) => {
1957 updates.updated_nodes.remove(&path);
1958 }
1959 SparseTrieUpdatesAction::InsertUpdated(path, branch_node) => {
1960 updates.updated_nodes.insert(path, branch_node);
1961 }
1962 }
1963 }
1964 };
1965 }
1966
1967 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, ret)]
1969 fn update_upper_subtrie_hashes(&mut self, prefix_set: &mut PrefixSet) -> RlpNode {
1970 trace!(target: "trie::parallel_sparse", "Updating upper subtrie hashes");
1971
1972 debug_assert!(self.upper_subtrie.inner.buffers.path_stack.is_empty());
1973 self.upper_subtrie.inner.buffers.path_stack.push(RlpNodePathStackItem {
1974 path: Nibbles::default(), is_in_prefix_set: None,
1976 });
1977
1978 #[cfg(feature = "metrics")]
1979 let start = std::time::Instant::now();
1980
1981 let mut update_actions_buf =
1982 self.updates_enabled().then(|| self.update_actions_buffers.pop().unwrap_or_default());
1983
1984 while let Some(stack_item) = self.upper_subtrie.inner.buffers.path_stack.pop() {
1985 let path = stack_item.path;
1986 let node = if path.len() < UPPER_TRIE_MAX_DEPTH {
1987 self.upper_subtrie.nodes.get_mut(&path).expect("upper subtrie node must exist")
1988 } else {
1989 let index = path_subtrie_index_unchecked(&path);
1990 let node = self.lower_subtries[index]
1991 .as_revealed_mut()
1992 .expect("lower subtrie must exist")
1993 .nodes
1994 .get_mut(&path)
1995 .expect("lower subtrie node must exist");
1996 debug_assert!(
1999 node.hash().is_some(),
2000 "Lower subtrie root node at path {path:?} has no hash"
2001 );
2002 node
2003 };
2004
2005 self.upper_subtrie.inner.rlp_node(
2007 prefix_set,
2008 &mut update_actions_buf,
2009 stack_item,
2010 node,
2011 &self.branch_node_masks,
2012 );
2013 }
2014
2015 if let Some(mut update_actions_buf) = update_actions_buf {
2018 self.apply_subtrie_update_actions(
2019 #[allow(clippy::iter_with_drain)]
2020 update_actions_buf.drain(..),
2021 );
2022 self.update_actions_buffers.push(update_actions_buf);
2023 }
2024
2025 #[cfg(feature = "metrics")]
2026 self.metrics.subtrie_upper_hash_latency.record(start.elapsed());
2027
2028 debug_assert_eq!(self.upper_subtrie.inner.buffers.rlp_node_stack.len(), 1);
2029 self.upper_subtrie.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
2030 }
2031
2032 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(prefix_set_len = prefix_set.len()))]
2046 fn take_changed_lower_subtries(
2047 &mut self,
2048 prefix_set: &mut PrefixSet,
2049 ) -> (Vec<ChangedSubtrie>, PrefixSetMut) {
2050 if prefix_set.is_empty() {
2053 return Default::default();
2054 }
2055
2056 let prefix_set_clone = prefix_set.clone();
2058 let mut prefix_set_iter = prefix_set_clone.into_iter().copied().peekable();
2059 let mut changed_subtries = Vec::new();
2060 let mut unchanged_prefix_set = PrefixSetMut::default();
2061 let updates_enabled = self.updates_enabled();
2062
2063 for (index, subtrie) in self.lower_subtries.iter_mut().enumerate() {
2064 if let Some(subtrie) = subtrie.take_revealed_if(|subtrie| {
2065 prefix_set.contains(&subtrie.path) ||
2066 subtrie.nodes.get(&subtrie.path).is_some_and(|n| n.hash().is_none())
2067 }) {
2068 let prefix_set = if prefix_set.all() {
2069 unchanged_prefix_set = PrefixSetMut::all();
2070 PrefixSetMut::all()
2071 } else {
2072 let mut new_prefix_set = Vec::new();
2077 while let Some(key) = prefix_set_iter.peek() {
2078 if key.starts_with(&subtrie.path) {
2079 new_prefix_set.push(prefix_set_iter.next().unwrap());
2081 } else if new_prefix_set.is_empty() && key < &subtrie.path {
2082 unchanged_prefix_set.insert(prefix_set_iter.next().unwrap());
2086 } else {
2087 break
2091 }
2092 }
2093 PrefixSetMut::from(new_prefix_set)
2094 }
2095 .freeze();
2096
2097 match subtrie.nodes.get(&subtrie.path) {
2100 Some(SparseNode::Extension { key, .. } | SparseNode::Leaf { key, .. }) => {
2101 unchanged_prefix_set.insert(subtrie.path.join(key));
2102 }
2103 Some(SparseNode::Branch { .. }) => {
2104 unchanged_prefix_set.insert(subtrie.path);
2105 }
2106 _ => {}
2107 }
2108
2109 let update_actions_buf =
2110 updates_enabled.then(|| self.update_actions_buffers.pop().unwrap_or_default());
2111
2112 changed_subtries.push(ChangedSubtrie {
2113 index,
2114 subtrie,
2115 prefix_set,
2116 update_actions_buf,
2117 });
2118 }
2119 }
2120
2121 unchanged_prefix_set.extend_keys(prefix_set_iter);
2123
2124 (changed_subtries, unchanged_prefix_set)
2125 }
2126
2127 #[cfg(test)]
2129 fn all_nodes(&self) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
2130 let mut nodes = vec![];
2131 for subtrie in self.lower_subtries.iter().filter_map(LowerSparseSubtrie::as_revealed_ref) {
2132 nodes.extend(subtrie.nodes.iter())
2133 }
2134 nodes.extend(self.upper_subtrie.nodes.iter());
2135 nodes
2136 }
2137
2138 fn reveal_upper_node(
2155 &mut self,
2156 path: Nibbles,
2157 node: &TrieNode,
2158 masks: Option<BranchNodeMasks>,
2159 ) -> SparseTrieResult<()> {
2160 if !self.is_path_reachable_from_upper(&path) {
2163 return Ok(())
2164 }
2165
2166 if !self.upper_subtrie.reveal_node(path, node, masks)? {
2168 return Ok(())
2169 }
2170
2171 match node {
2176 TrieNode::Branch(branch) => {
2177 if !SparseSubtrieType::path_len_is_upper(path.len() + 1) {
2181 let mut stack_ptr = branch.as_ref().first_child_index();
2182 for idx in branch.state_mask.iter() {
2183 let mut child_path = path;
2184 child_path.push_unchecked(idx);
2185 self.lower_subtrie_for_path_mut(&child_path)
2186 .expect("child_path must have a lower subtrie")
2187 .reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?;
2188 stack_ptr += 1;
2189 }
2190 }
2191 }
2192 TrieNode::Extension(ext) => {
2193 let mut child_path = path;
2194 child_path.extend(&ext.key);
2195 if let Some(subtrie) = self.lower_subtrie_for_path_mut(&child_path) {
2196 subtrie.reveal_node_or_hash(child_path, &ext.child)?;
2197 }
2198 }
2199 TrieNode::EmptyRoot | TrieNode::Leaf(_) => (),
2200 }
2201
2202 Ok(())
2203 }
2204
2205 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
2208 fn insert_changed_subtries(
2209 &mut self,
2210 changed_subtries: impl IntoIterator<Item = ChangedSubtrie>,
2211 ) {
2212 for ChangedSubtrie { index, subtrie, update_actions_buf, .. } in changed_subtries {
2213 if let Some(mut update_actions_buf) = update_actions_buf {
2214 self.apply_subtrie_update_actions(
2215 #[allow(clippy::iter_with_drain)]
2216 update_actions_buf.drain(..),
2217 );
2218 self.update_actions_buffers.push(update_actions_buf);
2219 }
2220
2221 self.lower_subtries[index] = LowerSparseSubtrie::Revealed(subtrie);
2222 self.subtrie_heat.mark_modified(index);
2223 }
2224 }
2225
2226 pub fn memory_size(&self) -> usize {
2238 let mut size = core::mem::size_of::<Self>();
2239
2240 size += self.upper_subtrie.memory_size();
2242
2243 for subtrie in self.lower_subtries.iter() {
2245 size += subtrie.memory_size();
2246 }
2247
2248 size += self.prefix_set.len() * core::mem::size_of::<Nibbles>();
2250
2251 size += self.branch_node_masks.len() *
2253 (core::mem::size_of::<Nibbles>() + core::mem::size_of::<BranchNodeMasks>());
2254
2255 if let Some(updates) = &self.updates {
2257 size += updates.updated_nodes.len() *
2258 (core::mem::size_of::<Nibbles>() + core::mem::size_of::<BranchNodeCompact>());
2259 size += updates.removed_nodes.len() * core::mem::size_of::<Nibbles>();
2260 }
2261
2262 for buf in &self.update_actions_buffers {
2264 size += buf.capacity() * core::mem::size_of::<SparseTrieUpdatesAction>();
2265 }
2266
2267 size
2268 }
2269
2270 fn is_path_reachable_from_upper(&self, path: &Nibbles) -> bool {
2272 let mut current = Nibbles::default();
2273 while current.len() < path.len() {
2274 let Some(node) = self.upper_subtrie.nodes.get(¤t) else { return false };
2275 match node {
2276 SparseNode::Branch { state_mask, .. } => {
2277 if !state_mask.is_bit_set(path.get_unchecked(current.len())) {
2278 return false
2279 }
2280
2281 current.push_unchecked(path.get_unchecked(current.len()));
2282 }
2283 SparseNode::Extension { key, .. } => {
2284 if *key != path.slice(current.len()..current.len() + key.len()) {
2285 return false
2286 }
2287 current.extend(key);
2288 }
2289 SparseNode::Hash(_) | SparseNode::Empty | SparseNode::Leaf { .. } => return false,
2290 }
2291 }
2292 true
2293 }
2294
2295 fn is_boundary_leaf_reachable(
2301 upper_nodes: &HashMap<Nibbles, SparseNode>,
2302 path: &Nibbles,
2303 node: &TrieNode,
2304 ) -> bool {
2305 debug_assert_eq!(path.len(), UPPER_TRIE_MAX_DEPTH);
2306
2307 if !matches!(node, TrieNode::Leaf(_)) {
2308 return true
2309 }
2310
2311 let parent_path = path.slice(..path.len() - 1);
2312 let leaf_nibble = path.get_unchecked(path.len() - 1);
2313
2314 match upper_nodes.get(&parent_path) {
2315 Some(SparseNode::Branch { state_mask, .. }) => state_mask.is_bit_set(leaf_nibble),
2316 _ => false,
2317 }
2318 }
2319
2320 fn reachable_subtries(&self) -> SubtriesBitmap {
2323 let mut reachable = SubtriesBitmap::default();
2324
2325 let mut stack = Vec::new();
2326 stack.push(Nibbles::default());
2327
2328 while let Some(current) = stack.pop() {
2329 let Some(node) = self.upper_subtrie.nodes.get(¤t) else { continue };
2330 match node {
2331 SparseNode::Branch { state_mask, .. } => {
2332 for idx in state_mask.iter() {
2333 let mut next = current;
2334 next.push_unchecked(idx);
2335 if next.len() >= UPPER_TRIE_MAX_DEPTH {
2336 reachable.set(path_subtrie_index_unchecked(&next));
2337 } else {
2338 stack.push(next);
2339 }
2340 }
2341 }
2342 SparseNode::Extension { key, .. } => {
2343 let mut next = current;
2344 next.extend(key);
2345 if next.len() >= UPPER_TRIE_MAX_DEPTH {
2346 reachable.set(path_subtrie_index_unchecked(&next));
2347 } else {
2348 stack.push(next);
2349 }
2350 }
2351 SparseNode::Hash(_) | SparseNode::Empty | SparseNode::Leaf { .. } => {}
2352 };
2353 }
2354
2355 reachable
2356 }
2357}
2358
2359#[derive(Clone, Default, PartialEq, Eq, Debug)]
2361struct SubtriesBitmap(U256);
2362
2363impl SubtriesBitmap {
2364 #[inline]
2366 fn set(&mut self, idx: usize) {
2367 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2368 self.0.set_bit(idx, true);
2369 }
2370
2371 #[inline]
2373 fn get(&self, idx: usize) -> bool {
2374 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2375 self.0.bit(idx)
2376 }
2377
2378 #[inline]
2380 const fn clear(&mut self) {
2381 self.0 = U256::ZERO;
2382 }
2383}
2384
2385#[derive(Clone, PartialEq, Eq, Debug)]
2394struct SubtrieModifications {
2395 heat: [u8; NUM_LOWER_SUBTRIES],
2397 modified: SubtriesBitmap,
2399}
2400
2401impl Default for SubtrieModifications {
2402 fn default() -> Self {
2403 Self { heat: [0; NUM_LOWER_SUBTRIES], modified: SubtriesBitmap::default() }
2404 }
2405}
2406
2407impl SubtrieModifications {
2408 #[inline]
2410 fn mark_modified(&mut self, idx: usize) {
2411 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2412 self.modified.set(idx);
2413 self.heat[idx] = self.heat[idx].saturating_add(1);
2414 }
2415
2416 #[inline]
2418 fn is_hot(&self, idx: usize) -> bool {
2419 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2420 self.heat[idx] > 0
2421 }
2422
2423 fn decay_and_reset(&mut self) {
2426 for (idx, heat) in self.heat.iter_mut().enumerate() {
2427 if !self.modified.get(idx) {
2428 *heat = heat.saturating_sub(1);
2429 }
2430 }
2431 self.modified.clear();
2432 }
2433
2434 const fn clear(&mut self) {
2436 self.heat = [0; NUM_LOWER_SUBTRIES];
2437 self.modified.clear();
2438 }
2439}
2440
2441#[derive(Clone, PartialEq, Eq, Debug, Default)]
2444pub struct SparseSubtrie {
2445 pub(crate) path: Nibbles,
2453 nodes: HashMap<Nibbles, SparseNode>,
2455 inner: SparseSubtrieInner,
2457}
2458
2459enum FindNextToLeafOutcome {
2462 Found,
2464 ContinueFrom(Nibbles),
2466 NotFound,
2469 BlindedNode(B256),
2472}
2473
2474impl SparseSubtrie {
2475 pub(crate) fn new(path: Nibbles) -> Self {
2477 Self { path, ..Default::default() }
2478 }
2479
2480 pub(crate) fn is_empty(&self) -> bool {
2482 self.nodes.is_empty()
2483 }
2484
2485 fn is_child_same_level(current_path: &Nibbles, child_path: &Nibbles) -> bool {
2487 let current_level = core::mem::discriminant(&SparseSubtrieType::from_path(current_path));
2488 let child_level = core::mem::discriminant(&SparseSubtrieType::from_path(child_path));
2489 current_level == child_level
2490 }
2491
2492 fn is_leaf_reachable_from_parent(&self, path: &Nibbles) -> bool {
2501 if path.is_empty() {
2502 return true
2503 }
2504
2505 let parent_path = path.slice(..path.len() - 1);
2506 let leaf_nibble = path.get_unchecked(path.len() - 1);
2507
2508 match self.nodes.get(&parent_path) {
2509 Some(SparseNode::Branch { state_mask, .. }) => state_mask.is_bit_set(leaf_nibble),
2510 _ => false,
2511 }
2512 }
2513
2514 pub fn update_leaf(
2530 &mut self,
2531 full_path: Nibbles,
2532 value: Vec<u8>,
2533 provider: impl TrieNodeProvider,
2534 retain_updates: bool,
2535 ) -> SparseTrieResult<Option<(Nibbles, BranchNodeMasks)>> {
2536 debug_assert!(full_path.starts_with(&self.path));
2537
2538 if let Entry::Occupied(mut e) = self.inner.values.entry(full_path) {
2540 e.insert(value);
2541 return Ok(None)
2542 }
2543
2544 let mut current = Some(self.path);
2546 let mut revealed = None;
2547
2548 let mut inserted_nodes: Vec<Nibbles> = Vec::new();
2550 let mut modified_original: Option<(Nibbles, SparseNode)> = None;
2551
2552 while let Some(current_path) = current {
2553 if modified_original.is_none() &&
2555 let Some(node) = self.nodes.get(¤t_path)
2556 {
2557 modified_original = Some((current_path, node.clone()));
2558 }
2559
2560 let step_result = self.update_next_node(current_path, &full_path, retain_updates);
2561
2562 if let Err(e) = step_result {
2564 self.rollback_leaf_insert(&full_path, &inserted_nodes, modified_original.take());
2565 return Err(e);
2566 }
2567
2568 match step_result? {
2569 LeafUpdateStep::Continue { next_node } => {
2570 current = Some(next_node);
2571 modified_original = None;
2573 }
2574 LeafUpdateStep::Complete { inserted_nodes: new_inserted, reveal_path } => {
2575 inserted_nodes.extend(new_inserted);
2576
2577 if let Some(reveal_path) = reveal_path &&
2578 self.nodes.get(&reveal_path).expect("node must exist").is_hash()
2579 {
2580 debug!(
2581 target: "trie::parallel_sparse",
2582 child_path = ?reveal_path,
2583 leaf_full_path = ?full_path,
2584 "Extension node child not revealed in update_leaf, falling back to db",
2585 );
2586 let revealed_node = match provider.trie_node(&reveal_path) {
2587 Ok(node) => node,
2588 Err(e) => {
2589 self.rollback_leaf_insert(
2590 &full_path,
2591 &inserted_nodes,
2592 modified_original.take(),
2593 );
2594 return Err(e);
2595 }
2596 };
2597 if let Some(RevealedNode { node, tree_mask, hash_mask }) = revealed_node {
2598 let decoded = match TrieNode::decode(&mut &node[..]) {
2599 Ok(d) => d,
2600 Err(e) => {
2601 self.rollback_leaf_insert(
2602 &full_path,
2603 &inserted_nodes,
2604 modified_original.take(),
2605 );
2606 return Err(e.into());
2607 }
2608 };
2609 trace!(
2610 target: "trie::parallel_sparse",
2611 ?reveal_path,
2612 ?decoded,
2613 ?tree_mask,
2614 ?hash_mask,
2615 "Revealing child (from lower)",
2616 );
2617 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
2618 if let Err(e) = self.reveal_node(reveal_path, &decoded, masks) {
2619 self.rollback_leaf_insert(
2620 &full_path,
2621 &inserted_nodes,
2622 modified_original.take(),
2623 );
2624 return Err(e);
2625 }
2626
2627 debug_assert_eq!(
2628 revealed, None,
2629 "Only a single blinded node should be revealed during update_leaf"
2630 );
2631 revealed = masks.map(|masks| (reveal_path, masks));
2632 } else {
2633 self.rollback_leaf_insert(
2634 &full_path,
2635 &inserted_nodes,
2636 modified_original.take(),
2637 );
2638 return Err(SparseTrieErrorKind::NodeNotFoundInProvider {
2639 path: reveal_path,
2640 }
2641 .into())
2642 }
2643 }
2644
2645 current = None;
2646 }
2647 LeafUpdateStep::NodeNotFound => {
2648 current = None;
2649 }
2650 }
2651 }
2652
2653 self.inner.values.insert(full_path, value);
2655
2656 Ok(revealed)
2657 }
2658
2659 fn rollback_leaf_insert(
2664 &mut self,
2665 full_path: &Nibbles,
2666 inserted_nodes: &[Nibbles],
2667 modified_original: Option<(Nibbles, SparseNode)>,
2668 ) {
2669 self.inner.values.remove(full_path);
2671
2672 for node_path in inserted_nodes {
2674 self.nodes.remove(node_path);
2675 }
2676
2677 if let Some((path, original_node)) = modified_original {
2679 self.nodes.insert(path, original_node);
2680 }
2681 }
2682
2683 fn update_next_node(
2690 &mut self,
2691 mut current: Nibbles,
2692 path: &Nibbles,
2693 retain_updates: bool,
2694 ) -> SparseTrieResult<LeafUpdateStep> {
2695 debug_assert!(path.starts_with(&self.path));
2696 debug_assert!(current.starts_with(&self.path));
2697 debug_assert!(path.starts_with(¤t));
2698 let Some(node) = self.nodes.get_mut(¤t) else {
2699 return Ok(LeafUpdateStep::NodeNotFound);
2700 };
2701 match node {
2702 SparseNode::Empty => {
2703 let path = path.slice(self.path.len()..);
2706 *node = SparseNode::new_leaf(path);
2707 Ok(LeafUpdateStep::complete_with_insertions(vec![current], None))
2708 }
2709 SparseNode::Hash(hash) => {
2710 Err(SparseTrieErrorKind::BlindedNode { path: current, hash: *hash }.into())
2711 }
2712 SparseNode::Leaf { key: current_key, .. } => {
2713 current.extend(current_key);
2714
2715 debug_assert!(
2717 ¤t != path,
2718 "we already checked leaf presence in the beginning"
2719 );
2720
2721 let common = current.common_prefix_length(path);
2723
2724 let new_ext_key = current.slice(current.len() - current_key.len()..common);
2726 *node = SparseNode::new_ext(new_ext_key);
2727
2728 self.nodes.reserve(3);
2730 let branch_path = current.slice(..common);
2731 let new_leaf_path = path.slice(..=common);
2732 let existing_leaf_path = current.slice(..=common);
2733
2734 self.nodes.insert(
2735 branch_path,
2736 SparseNode::new_split_branch(
2737 current.get_unchecked(common),
2738 path.get_unchecked(common),
2739 ),
2740 );
2741 self.nodes.insert(new_leaf_path, SparseNode::new_leaf(path.slice(common + 1..)));
2742 self.nodes
2743 .insert(existing_leaf_path, SparseNode::new_leaf(current.slice(common + 1..)));
2744
2745 Ok(LeafUpdateStep::complete_with_insertions(
2746 vec![branch_path, new_leaf_path, existing_leaf_path],
2747 None,
2748 ))
2749 }
2750 SparseNode::Extension { key, .. } => {
2751 current.extend(key);
2752
2753 if !path.starts_with(¤t) {
2754 let common = current.common_prefix_length(path);
2756 *key = current.slice(current.len() - key.len()..common);
2757
2758 let reveal_path = retain_updates.then_some(current);
2762
2763 self.nodes.reserve(3);
2766 let branch_path = current.slice(..common);
2767 let new_leaf_path = path.slice(..=common);
2768 let branch = SparseNode::new_split_branch(
2769 current.get_unchecked(common),
2770 path.get_unchecked(common),
2771 );
2772
2773 self.nodes.insert(branch_path, branch);
2774
2775 let new_leaf = SparseNode::new_leaf(path.slice(common + 1..));
2777 self.nodes.insert(new_leaf_path, new_leaf);
2778
2779 let mut inserted_nodes = vec![branch_path, new_leaf_path];
2780
2781 let key = current.slice(common + 1..);
2783 if !key.is_empty() {
2784 let ext_path = current.slice(..=common);
2785 self.nodes.insert(ext_path, SparseNode::new_ext(key));
2786 inserted_nodes.push(ext_path);
2787 }
2788
2789 return Ok(LeafUpdateStep::complete_with_insertions(inserted_nodes, reveal_path))
2790 }
2791
2792 Ok(LeafUpdateStep::continue_with(current))
2793 }
2794 SparseNode::Branch { state_mask, .. } => {
2795 let nibble = path.get_unchecked(current.len());
2796 current.push_unchecked(nibble);
2797 if !state_mask.is_bit_set(nibble) {
2798 state_mask.set_bit(nibble);
2799 let new_leaf = SparseNode::new_leaf(path.slice(current.len()..));
2800 self.nodes.insert(current, new_leaf);
2801 return Ok(LeafUpdateStep::complete_with_insertions(vec![current], None))
2802 }
2803
2804 Ok(LeafUpdateStep::continue_with(current))
2806 }
2807 }
2808 }
2809
2810 fn reveal_node(
2812 &mut self,
2813 path: Nibbles,
2814 node: &TrieNode,
2815 masks: Option<BranchNodeMasks>,
2816 ) -> SparseTrieResult<bool> {
2817 debug_assert!(path.starts_with(&self.path));
2818
2819 if self.nodes.get(&path).is_some_and(|node| !node.is_hash()) {
2821 return Ok(false)
2822 }
2823
2824 trace!(
2825 target: "trie::parallel_sparse",
2826 ?path,
2827 ?node,
2828 ?masks,
2829 "Revealing node",
2830 );
2831
2832 match node {
2833 TrieNode::EmptyRoot => {
2834 debug_assert!(path.is_empty());
2836 debug_assert!(self.path.is_empty());
2837 self.nodes.insert(path, SparseNode::Empty);
2838 }
2839 TrieNode::Branch(branch) => {
2840 match self.nodes.entry(path) {
2843 Entry::Occupied(mut entry) => match entry.get() {
2844 SparseNode::Hash(hash) => {
2846 entry.insert(SparseNode::Branch {
2847 state_mask: branch.state_mask,
2848 hash: Some(*hash),
2851 store_in_db_trie: Some(masks.is_some_and(|m| {
2852 !m.hash_mask.is_empty() || !m.tree_mask.is_empty()
2853 })),
2854 });
2855 }
2856 _ => unreachable!("checked that node is either a hash or non-existent"),
2857 },
2858 Entry::Vacant(entry) => {
2859 entry.insert(SparseNode::new_branch(branch.state_mask));
2860 }
2861 }
2862
2863 let mut stack_ptr = branch.as_ref().first_child_index();
2866 for idx in branch.state_mask.iter() {
2867 let mut child_path = path;
2868 child_path.push_unchecked(idx);
2869 if Self::is_child_same_level(&path, &child_path) {
2870 self.reveal_node_or_hash(child_path, &branch.stack[stack_ptr])?;
2873 }
2874 stack_ptr += 1;
2875 }
2876 }
2877 TrieNode::Extension(ext) => match self.nodes.entry(path) {
2878 Entry::Occupied(mut entry) => match entry.get() {
2879 SparseNode::Hash(hash) => {
2881 let mut child_path = *entry.key();
2882 child_path.extend(&ext.key);
2883 entry.insert(SparseNode::Extension {
2884 key: ext.key,
2885 hash: Some(*hash),
2888 store_in_db_trie: None,
2889 });
2890 if Self::is_child_same_level(&path, &child_path) {
2891 self.reveal_node_or_hash(child_path, &ext.child)?;
2892 }
2893 }
2894 _ => unreachable!("checked that node is either a hash or non-existent"),
2895 },
2896 Entry::Vacant(entry) => {
2897 let mut child_path = *entry.key();
2898 child_path.extend(&ext.key);
2899 entry.insert(SparseNode::new_ext(ext.key));
2900 if Self::is_child_same_level(&path, &child_path) {
2901 self.reveal_node_or_hash(child_path, &ext.child)?;
2902 }
2903 }
2904 },
2905 TrieNode::Leaf(leaf) => {
2906 if path.len() != UPPER_TRIE_MAX_DEPTH && !self.is_leaf_reachable_from_parent(&path)
2911 {
2912 trace!(
2913 target: "trie::parallel_sparse",
2914 ?path,
2915 "Leaf not reachable from parent branch, skipping",
2916 );
2917 return Ok(false)
2918 }
2919
2920 let mut full_key = path;
2921 full_key.extend(&leaf.key);
2922
2923 match self.inner.values.entry(full_key) {
2924 Entry::Occupied(_) => {
2925 trace!(
2926 target: "trie::parallel_sparse",
2927 ?path,
2928 ?full_key,
2929 "Leaf full key value already present, skipping",
2930 );
2931 return Ok(false)
2932 }
2933 Entry::Vacant(entry) => {
2934 entry.insert(leaf.value.clone());
2935 }
2936 }
2937
2938 match self.nodes.entry(path) {
2939 Entry::Occupied(mut entry) => match entry.get() {
2940 SparseNode::Hash(hash) => {
2942 entry.insert(SparseNode::Leaf {
2943 key: leaf.key,
2944 hash: Some(*hash),
2947 });
2948 }
2949 _ => unreachable!("checked that node is either a hash or non-existent"),
2950 },
2951 Entry::Vacant(entry) => {
2952 entry.insert(SparseNode::new_leaf(leaf.key));
2953 }
2954 }
2955 }
2956 }
2957
2958 Ok(true)
2959 }
2960
2961 fn reveal_node_or_hash(&mut self, path: Nibbles, child: &[u8]) -> SparseTrieResult<()> {
2980 if child.len() == B256::len_bytes() + 1 {
2981 let hash = B256::from_slice(&child[1..]);
2982 match self.nodes.entry(path) {
2983 Entry::Occupied(entry) => match entry.get() {
2984 SparseNode::Hash(previous_hash) if previous_hash != &hash => {
2986 return Err(SparseTrieErrorKind::Reveal {
2987 path: *entry.key(),
2988 node: Box::new(SparseNode::Hash(hash)),
2989 }
2990 .into())
2991 }
2992 _ => {}
2993 },
2994 Entry::Vacant(entry) => {
2995 entry.insert(SparseNode::Hash(hash));
2996 }
2997 }
2998 return Ok(())
2999 }
3000
3001 self.reveal_node(path, &TrieNode::decode(&mut &child[..])?, None)?;
3002
3003 Ok(())
3004 }
3005
3006 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(root = ?self.path), ret)]
3028 fn update_hashes(
3029 &mut self,
3030 prefix_set: &mut PrefixSet,
3031 update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
3032 branch_node_masks: &BranchNodeMasksMap,
3033 ) -> RlpNode {
3034 trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
3035
3036 debug_assert!(prefix_set.iter().all(|path| path.starts_with(&self.path)));
3037
3038 debug_assert!(self.inner.buffers.path_stack.is_empty());
3039 self.inner
3040 .buffers
3041 .path_stack
3042 .push(RlpNodePathStackItem { path: self.path, is_in_prefix_set: None });
3043
3044 while let Some(stack_item) = self.inner.buffers.path_stack.pop() {
3045 let path = stack_item.path;
3046 let node = self
3047 .nodes
3048 .get_mut(&path)
3049 .unwrap_or_else(|| panic!("node at path {path:?} does not exist"));
3050
3051 self.inner.rlp_node(prefix_set, update_actions, stack_item, node, branch_node_masks);
3052 }
3053
3054 debug_assert_eq!(self.inner.buffers.rlp_node_stack.len(), 1);
3055 self.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
3056 }
3057
3058 fn wipe(&mut self) {
3061 self.nodes = HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]);
3062 self.inner.clear();
3063 }
3064
3065 pub(crate) fn clear(&mut self) {
3067 self.nodes.clear();
3068 self.inner.clear();
3069 }
3070
3071 pub(crate) fn shrink_nodes_to(&mut self, size: usize) {
3073 self.nodes.shrink_to(size);
3074 }
3075
3076 pub(crate) fn shrink_values_to(&mut self, size: usize) {
3078 self.inner.values.shrink_to(size);
3079 }
3080
3081 pub(crate) fn memory_size(&self) -> usize {
3083 let mut size = core::mem::size_of::<Self>();
3084
3085 for (path, node) in &self.nodes {
3087 size += core::mem::size_of::<Nibbles>();
3088 size += path.len(); size += node.memory_size();
3090 }
3091
3092 for (path, value) in &self.inner.values {
3094 size += core::mem::size_of::<Nibbles>();
3095 size += path.len(); size += core::mem::size_of::<Vec<u8>>() + value.capacity();
3097 }
3098
3099 size += self.inner.buffers.memory_size();
3101
3102 size
3103 }
3104}
3105
3106#[derive(Clone, PartialEq, Eq, Debug, Default)]
3109struct SparseSubtrieInner {
3110 values: HashMap<Nibbles, Vec<u8>>,
3113 buffers: SparseSubtrieBuffers,
3115}
3116
3117impl SparseSubtrieInner {
3118 fn rlp_node(
3148 &mut self,
3149 prefix_set: &mut PrefixSet,
3150 update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
3151 mut stack_item: RlpNodePathStackItem,
3152 node: &mut SparseNode,
3153 branch_node_masks: &BranchNodeMasksMap,
3154 ) {
3155 let path = stack_item.path;
3156 trace!(
3157 target: "trie::parallel_sparse",
3158 ?path,
3159 ?node,
3160 "Calculating node RLP"
3161 );
3162
3163 let mut prefix_set_contains = |path: &Nibbles| {
3167 *stack_item.is_in_prefix_set.get_or_insert_with(|| prefix_set.contains(path))
3168 };
3169
3170 let (rlp_node, node_type) = match node {
3171 SparseNode::Empty => (RlpNode::word_rlp(&EMPTY_ROOT_HASH), SparseNodeType::Empty),
3172 SparseNode::Hash(hash) => {
3173 (RlpNode::word_rlp(hash), SparseNodeType::Hash)
3175 }
3176 SparseNode::Leaf { key, hash } => {
3177 let mut path = path;
3178 path.extend(key);
3179 let value = self.values.get(&path);
3180 if let Some(hash) = hash.filter(|_| !prefix_set_contains(&path) || value.is_none())
3181 {
3182 (RlpNode::word_rlp(&hash), SparseNodeType::Leaf)
3186 } else {
3187 let value = self.values.get(&path).unwrap();
3189 self.buffers.rlp_buf.clear();
3190 let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.buffers.rlp_buf);
3191 *hash = rlp_node.as_hash();
3192 trace!(
3193 target: "trie::parallel_sparse",
3194 ?path,
3195 ?key,
3196 value = %alloy_primitives::hex::encode(value),
3197 ?hash,
3198 "Calculated leaf hash",
3199 );
3200 (rlp_node, SparseNodeType::Leaf)
3201 }
3202 }
3203 SparseNode::Extension { key, hash, store_in_db_trie } => {
3204 let mut child_path = path;
3205 child_path.extend(key);
3206 if let Some((hash, store_in_db_trie)) =
3207 hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
3208 {
3209 (
3212 RlpNode::word_rlp(&hash),
3213 SparseNodeType::Extension { store_in_db_trie: Some(store_in_db_trie) },
3214 )
3215 } else if self.buffers.rlp_node_stack.last().is_some_and(|e| e.path == child_path) {
3216 let RlpNodeStackItem { path: _, rlp_node: child, node_type: child_node_type } =
3219 self.buffers.rlp_node_stack.pop().unwrap();
3220 self.buffers.rlp_buf.clear();
3221 let rlp_node =
3222 ExtensionNodeRef::new(key, &child).rlp(&mut self.buffers.rlp_buf);
3223 *hash = rlp_node.as_hash();
3224
3225 let store_in_db_trie_value = child_node_type.store_in_db_trie();
3226
3227 trace!(
3228 target: "trie::parallel_sparse",
3229 ?path,
3230 ?child_path,
3231 ?child_node_type,
3232 "Extension node"
3233 );
3234
3235 *store_in_db_trie = store_in_db_trie_value;
3236
3237 (
3238 rlp_node,
3239 SparseNodeType::Extension {
3240 store_in_db_trie: store_in_db_trie_value,
3243 },
3244 )
3245 } else {
3246 self.buffers.path_stack.extend([
3249 RlpNodePathStackItem {
3250 path,
3251 is_in_prefix_set: Some(prefix_set_contains(&path)),
3252 },
3253 RlpNodePathStackItem { path: child_path, is_in_prefix_set: None },
3254 ]);
3255 return
3256 }
3257 }
3258 SparseNode::Branch { state_mask, hash, store_in_db_trie } => {
3259 if let Some((hash, store_in_db_trie)) =
3260 hash.zip(*store_in_db_trie).filter(|_| !prefix_set_contains(&path))
3261 {
3262 let rlp_node = RlpNode::word_rlp(&hash);
3263 let node_type =
3264 SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie) };
3265
3266 trace!(
3267 target: "trie::parallel_sparse",
3268 ?path,
3269 ?node_type,
3270 ?rlp_node,
3271 "Adding node to RLP node stack (cached branch)"
3272 );
3273
3274 self.buffers.rlp_node_stack.push(RlpNodeStackItem {
3277 path,
3278 rlp_node,
3279 node_type,
3280 });
3281 return
3282 }
3283
3284 let retain_updates = update_actions.is_some() && prefix_set_contains(&path);
3285
3286 self.buffers.branch_child_buf.clear();
3287 for bit in state_mask.iter().rev() {
3290 let mut child = path;
3291 child.push_unchecked(bit);
3292 self.buffers.branch_child_buf.push(child);
3293 }
3294
3295 self.buffers
3296 .branch_value_stack_buf
3297 .resize(self.buffers.branch_child_buf.len(), Default::default());
3298 let mut added_children = false;
3299
3300 let mut tree_mask = TrieMask::default();
3301 let mut hash_mask = TrieMask::default();
3302 let mut hashes = Vec::new();
3303
3304 let mut path_masks_storage = None;
3306 let mut path_masks =
3307 || *path_masks_storage.get_or_insert_with(|| branch_node_masks.get(&path));
3308
3309 for (i, child_path) in self.buffers.branch_child_buf.iter().enumerate() {
3310 if self.buffers.rlp_node_stack.last().is_some_and(|e| &e.path == child_path) {
3311 let RlpNodeStackItem {
3312 path: _,
3313 rlp_node: child,
3314 node_type: child_node_type,
3315 } = self.buffers.rlp_node_stack.pop().unwrap();
3316
3317 if retain_updates {
3319 let last_child_nibble = child_path.last().unwrap();
3321
3322 let should_set_tree_mask_bit = if let Some(store_in_db_trie) =
3324 child_node_type.store_in_db_trie()
3325 {
3326 store_in_db_trie
3329 } else {
3330 child_node_type.is_hash() &&
3332 path_masks().is_some_and(|masks| {
3333 masks.tree_mask.is_bit_set(last_child_nibble)
3334 })
3335 };
3336 if should_set_tree_mask_bit {
3337 tree_mask.set_bit(last_child_nibble);
3338 }
3339
3340 let hash = child.as_hash().filter(|_| {
3344 child_node_type.is_branch() ||
3345 (child_node_type.is_hash() &&
3346 path_masks().is_some_and(|masks| {
3347 masks.hash_mask.is_bit_set(last_child_nibble)
3348 }))
3349 });
3350 if let Some(hash) = hash {
3351 hash_mask.set_bit(last_child_nibble);
3352 hashes.push(hash);
3353 }
3354 }
3355
3356 let original_idx = self.buffers.branch_child_buf.len() - i - 1;
3360 self.buffers.branch_value_stack_buf[original_idx] = child;
3361 added_children = true;
3362 } else {
3363 debug_assert!(!added_children);
3366 self.buffers.path_stack.push(RlpNodePathStackItem {
3367 path,
3368 is_in_prefix_set: Some(prefix_set_contains(&path)),
3369 });
3370 self.buffers.path_stack.extend(
3371 self.buffers
3372 .branch_child_buf
3373 .drain(..)
3374 .map(|path| RlpNodePathStackItem { path, is_in_prefix_set: None }),
3375 );
3376 return
3377 }
3378 }
3379
3380 trace!(
3381 target: "trie::parallel_sparse",
3382 ?path,
3383 ?tree_mask,
3384 ?hash_mask,
3385 "Branch node masks"
3386 );
3387
3388 self.buffers.rlp_buf.clear();
3391 let branch_node_ref =
3392 BranchNodeRef::new(&self.buffers.branch_value_stack_buf, *state_mask);
3393 let rlp_node = branch_node_ref.rlp(&mut self.buffers.rlp_buf);
3394 *hash = rlp_node.as_hash();
3395
3396 let store_in_db_trie_value = if let Some(update_actions) =
3399 update_actions.as_mut().filter(|_| retain_updates && !path.is_empty())
3400 {
3401 let store_in_db_trie = !tree_mask.is_empty() || !hash_mask.is_empty();
3402 if store_in_db_trie {
3403 hashes.reverse();
3406 let branch_node = BranchNodeCompact::new(
3407 *state_mask,
3408 tree_mask,
3409 hash_mask,
3410 hashes,
3411 hash.filter(|_| path.is_empty()),
3412 );
3413 update_actions
3414 .push(SparseTrieUpdatesAction::InsertUpdated(path, branch_node));
3415 } else {
3416 let prev_had_masks = path_masks()
3418 .is_some_and(|m| !m.tree_mask.is_empty() || !m.hash_mask.is_empty());
3419 if prev_had_masks {
3420 update_actions.push(SparseTrieUpdatesAction::InsertRemoved(path));
3422 } else {
3423 update_actions.push(SparseTrieUpdatesAction::RemoveUpdated(path));
3425 }
3426 }
3427
3428 store_in_db_trie
3429 } else {
3430 false
3431 };
3432 *store_in_db_trie = Some(store_in_db_trie_value);
3433
3434 (
3435 rlp_node,
3436 SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie_value) },
3437 )
3438 }
3439 };
3440
3441 trace!(
3442 target: "trie::parallel_sparse",
3443 ?path,
3444 ?node_type,
3445 ?rlp_node,
3446 "Adding node to RLP node stack"
3447 );
3448 self.buffers.rlp_node_stack.push(RlpNodeStackItem { path, rlp_node, node_type });
3449 }
3450
3451 fn clear(&mut self) {
3453 self.values.clear();
3454 self.buffers.clear();
3455 }
3456}
3457
3458#[derive(Clone, Debug, PartialEq, Eq, Default)]
3460pub enum LeafUpdateStep {
3461 Continue {
3463 next_node: Nibbles,
3465 },
3466 Complete {
3468 inserted_nodes: Vec<Nibbles>,
3470 reveal_path: Option<Nibbles>,
3472 },
3473 #[default]
3475 NodeNotFound,
3476}
3477
3478impl LeafUpdateStep {
3479 pub const fn continue_with(next_node: Nibbles) -> Self {
3481 Self::Continue { next_node }
3482 }
3483
3484 pub const fn complete_with_insertions(
3486 inserted_nodes: Vec<Nibbles>,
3487 reveal_path: Option<Nibbles>,
3488 ) -> Self {
3489 Self::Complete { inserted_nodes, reveal_path }
3490 }
3491}
3492
3493#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3502pub enum SparseSubtrieType {
3503 Upper,
3505 Lower(usize),
3508}
3509
3510impl SparseSubtrieType {
3511 pub const fn path_len_is_upper(len: usize) -> bool {
3516 len < UPPER_TRIE_MAX_DEPTH
3517 }
3518
3519 pub fn from_path(path: &Nibbles) -> Self {
3521 if Self::path_len_is_upper(path.len()) {
3522 Self::Upper
3523 } else {
3524 Self::Lower(path_subtrie_index_unchecked(path))
3525 }
3526 }
3527
3528 pub const fn lower_index(&self) -> Option<usize> {
3530 match self {
3531 Self::Upper => None,
3532 Self::Lower(index) => Some(*index),
3533 }
3534 }
3535}
3536
3537impl Ord for SparseSubtrieType {
3538 fn cmp(&self, other: &Self) -> Ordering {
3541 match (self, other) {
3542 (Self::Upper, Self::Upper) => Ordering::Equal,
3543 (Self::Upper, Self::Lower(_)) => Ordering::Less,
3544 (Self::Lower(_), Self::Upper) => Ordering::Greater,
3545 (Self::Lower(idx_a), Self::Lower(idx_b)) if idx_a == idx_b => Ordering::Equal,
3546 (Self::Lower(idx_a), Self::Lower(idx_b)) => idx_a.cmp(idx_b),
3547 }
3548 }
3549}
3550
3551impl PartialOrd for SparseSubtrieType {
3552 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3553 Some(self.cmp(other))
3554 }
3555}
3556
3557#[derive(Clone, PartialEq, Eq, Debug, Default)]
3561pub struct SparseSubtrieBuffers {
3562 path_stack: Vec<RlpNodePathStackItem>,
3564 rlp_node_stack: Vec<RlpNodeStackItem>,
3566 branch_child_buf: Vec<Nibbles>,
3568 branch_value_stack_buf: Vec<RlpNode>,
3570 rlp_buf: Vec<u8>,
3572}
3573
3574impl SparseSubtrieBuffers {
3575 fn clear(&mut self) {
3577 self.path_stack.clear();
3578 self.rlp_node_stack.clear();
3579 self.branch_child_buf.clear();
3580 self.branch_value_stack_buf.clear();
3581 self.rlp_buf.clear();
3582 }
3583
3584 const fn memory_size(&self) -> usize {
3586 let mut size = core::mem::size_of::<Self>();
3587
3588 size += self.path_stack.capacity() * core::mem::size_of::<RlpNodePathStackItem>();
3589 size += self.rlp_node_stack.capacity() * core::mem::size_of::<RlpNodeStackItem>();
3590 size += self.branch_child_buf.capacity() * core::mem::size_of::<Nibbles>();
3591 size += self.branch_value_stack_buf.capacity() * core::mem::size_of::<RlpNode>();
3592 size += self.rlp_buf.capacity();
3593
3594 size
3595 }
3596}
3597
3598#[derive(Clone, PartialEq, Eq, Debug)]
3600pub struct RlpNodePathStackItem {
3601 pub path: Nibbles,
3603 pub is_in_prefix_set: Option<bool>,
3605}
3606
3607#[derive(Debug)]
3609struct ChangedSubtrie {
3610 index: usize,
3612 subtrie: Box<SparseSubtrie>,
3614 prefix_set: PrefixSet,
3616 update_actions_buf: Option<Vec<SparseTrieUpdatesAction>>,
3619}
3620
3621fn path_subtrie_index_unchecked(path: &Nibbles) -> usize {
3628 debug_assert_eq!(UPPER_TRIE_MAX_DEPTH, 2);
3629 let idx = path.get_byte_unchecked(0) as usize;
3630 unsafe { core::hint::assert_unchecked(idx < NUM_LOWER_SUBTRIES) };
3632 idx
3633}
3634
3635fn is_strict_descendant_in(roots: &[(Nibbles, B256)], path: &Nibbles) -> bool {
3640 if roots.is_empty() {
3641 return false;
3642 }
3643 debug_assert!(roots.windows(2).all(|w| w[0].0 <= w[1].0), "roots must be sorted by path");
3644 let idx = roots.partition_point(|(root, _)| root <= path);
3645 if idx > 0 {
3646 let candidate = &roots[idx - 1].0;
3647 if path.starts_with(candidate) && path.len() > candidate.len() {
3648 return true;
3649 }
3650 }
3651 false
3652}
3653
3654fn starts_with_pruned_in(roots: &[(Nibbles, B256)], path: &Nibbles) -> bool {
3659 if roots.is_empty() {
3660 return false;
3661 }
3662 debug_assert!(roots.windows(2).all(|w| w[0].0 <= w[1].0), "roots must be sorted by path");
3663 let idx = roots.partition_point(|(root, _)| root <= path);
3664 if idx > 0 {
3665 let candidate = &roots[idx - 1].0;
3666 if path.starts_with(candidate) {
3667 return true;
3668 }
3669 }
3670 false
3671}
3672
3673#[derive(Clone, Debug, Eq, PartialEq)]
3675enum SparseTrieUpdatesAction {
3676 InsertRemoved(Nibbles),
3678 RemoveUpdated(Nibbles),
3681 InsertUpdated(Nibbles, BranchNodeCompact),
3683}
3684
3685#[cfg(test)]
3686mod tests {
3687 use super::{
3688 path_subtrie_index_unchecked, LowerSparseSubtrie, ParallelSparseTrie, SparseSubtrie,
3689 SparseSubtrieType,
3690 };
3691 use crate::{
3692 parallel::ChangedSubtrie,
3693 provider::{DefaultTrieNodeProvider, RevealedNode, TrieNodeProvider},
3694 LeafLookup, LeafLookupError, SparseNode, SparseTrie, SparseTrieUpdates,
3695 };
3696 use alloy_primitives::{
3697 b256, hex,
3698 map::{B256Set, DefaultHashBuilder, HashMap},
3699 B256, U256,
3700 };
3701 use alloy_rlp::{Decodable, Encodable};
3702 use alloy_trie::{BranchNodeCompact, Nibbles};
3703 use assert_matches::assert_matches;
3704 use itertools::Itertools;
3705 use proptest::{prelude::*, sample::SizeRange};
3706 use proptest_arbitrary_interop::arb;
3707 use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind};
3708 use reth_primitives_traits::Account;
3709 use reth_provider::{test_utils::create_test_provider_factory, TrieWriter};
3710 use reth_trie::{
3711 hashed_cursor::{noop::NoopHashedCursor, HashedPostStateCursor},
3712 node_iter::{TrieElement, TrieNodeIter},
3713 trie_cursor::{noop::NoopAccountTrieCursor, TrieCursor, TrieCursorFactory},
3714 walker::TrieWalker,
3715 HashedPostState,
3716 };
3717 use reth_trie_common::{
3718 prefix_set::PrefixSetMut,
3719 proof::{ProofNodes, ProofRetainer},
3720 updates::TrieUpdates,
3721 BranchNode, BranchNodeMasks, BranchNodeMasksMap, ExtensionNode, HashBuilder, LeafNode,
3722 ProofTrieNode, RlpNode, TrieMask, TrieNode, EMPTY_ROOT_HASH,
3723 };
3724 use reth_trie_db::DatabaseTrieCursorFactory;
3725 use std::collections::{BTreeMap, BTreeSet};
3726
3727 fn pad_nibbles_right(mut nibbles: Nibbles) -> Nibbles {
3729 nibbles.extend(&Nibbles::from_nibbles_unchecked(vec![
3730 0;
3731 B256::len_bytes() * 2 - nibbles.len()
3732 ]));
3733 nibbles
3734 }
3735
3736 #[derive(Debug, Clone)]
3741 struct MockTrieNodeProvider {
3742 nodes: HashMap<Nibbles, RevealedNode, DefaultHashBuilder>,
3744 }
3745
3746 impl MockTrieNodeProvider {
3747 fn new() -> Self {
3749 Self { nodes: HashMap::default() }
3750 }
3751
3752 fn add_revealed_node(&mut self, path: Nibbles, node: RevealedNode) {
3754 self.nodes.insert(path, node);
3755 }
3756 }
3757
3758 impl TrieNodeProvider for MockTrieNodeProvider {
3759 fn trie_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
3760 Ok(self.nodes.get(path).cloned())
3761 }
3762 }
3763
3764 fn create_account(nonce: u64) -> Account {
3765 Account { nonce, ..Default::default() }
3766 }
3767
3768 fn large_account_value() -> Vec<u8> {
3769 let account = Account {
3770 nonce: 0x123456789abcdef,
3771 balance: U256::from(0x123456789abcdef0123456789abcdef_u128),
3772 ..Default::default()
3773 };
3774 let mut buf = Vec::new();
3775 account.into_trie_account(EMPTY_ROOT_HASH).encode(&mut buf);
3776 buf
3777 }
3778
3779 fn encode_account_value(nonce: u64) -> Vec<u8> {
3780 let account = Account { nonce, ..Default::default() };
3781 let trie_account = account.into_trie_account(EMPTY_ROOT_HASH);
3782 let mut buf = Vec::new();
3783 trie_account.encode(&mut buf);
3784 buf
3785 }
3786
3787 #[derive(Default)]
3789 struct ParallelSparseTrieTestContext;
3790
3791 impl ParallelSparseTrieTestContext {
3792 fn assert_subtrie_exists(&self, trie: &ParallelSparseTrie, path: &Nibbles) {
3794 let idx = path_subtrie_index_unchecked(path);
3795 assert!(
3796 trie.lower_subtries[idx].as_revealed_ref().is_some(),
3797 "Expected lower subtrie at path {path:?} to exist",
3798 );
3799 }
3800
3801 fn get_subtrie<'a>(
3803 &self,
3804 trie: &'a ParallelSparseTrie,
3805 path: &Nibbles,
3806 ) -> &'a SparseSubtrie {
3807 let idx = path_subtrie_index_unchecked(path);
3808 trie.lower_subtries[idx]
3809 .as_revealed_ref()
3810 .unwrap_or_else(|| panic!("Lower subtrie at path {path:?} should exist"))
3811 }
3812
3813 fn assert_subtrie_path(
3815 &self,
3816 trie: &ParallelSparseTrie,
3817 subtrie_prefix: impl AsRef<[u8]>,
3818 expected_path: impl AsRef<[u8]>,
3819 ) {
3820 let subtrie_prefix = Nibbles::from_nibbles(subtrie_prefix);
3821 let expected_path = Nibbles::from_nibbles(expected_path);
3822 let idx = path_subtrie_index_unchecked(&subtrie_prefix);
3823
3824 let subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap_or_else(|| {
3825 panic!("Lower subtrie at prefix {subtrie_prefix:?} should exist")
3826 });
3827
3828 assert_eq!(
3829 subtrie.path, expected_path,
3830 "Subtrie at prefix {subtrie_prefix:?} should have path {expected_path:?}, but has {:?}",
3831 subtrie.path
3832 );
3833 }
3834
3835 fn create_test_leaves(&self, paths: &[&[u8]]) -> Vec<(Nibbles, Vec<u8>)> {
3837 paths
3838 .iter()
3839 .enumerate()
3840 .map(|(i, path)| (Nibbles::from_nibbles(path), encode_account_value(i as u64 + 1)))
3841 .collect()
3842 }
3843
3844 fn create_test_leaf(&self, path: impl AsRef<[u8]>, value_nonce: u64) -> (Nibbles, Vec<u8>) {
3846 (Nibbles::from_nibbles(path), encode_account_value(value_nonce))
3847 }
3848
3849 fn update_leaves(
3851 &self,
3852 trie: &mut ParallelSparseTrie,
3853 leaves: impl IntoIterator<Item = (Nibbles, Vec<u8>)>,
3854 ) {
3855 for (path, value) in leaves {
3856 trie.update_leaf(path, value, DefaultTrieNodeProvider).unwrap();
3857 }
3858 }
3859
3860 fn assert_subtrie<'a>(
3862 &self,
3863 trie: &'a ParallelSparseTrie,
3864 path: Nibbles,
3865 ) -> SubtrieAssertion<'a> {
3866 self.assert_subtrie_exists(trie, &path);
3867 let subtrie = self.get_subtrie(trie, &path);
3868 SubtrieAssertion::new(subtrie)
3869 }
3870
3871 fn assert_upper_subtrie<'a>(&self, trie: &'a ParallelSparseTrie) -> SubtrieAssertion<'a> {
3873 SubtrieAssertion::new(&trie.upper_subtrie)
3874 }
3875
3876 fn assert_with_hash_builder(
3878 &self,
3879 trie: &mut ParallelSparseTrie,
3880 hash_builder_root: B256,
3881 hash_builder_updates: TrieUpdates,
3882 hash_builder_proof_nodes: ProofNodes,
3883 ) {
3884 assert_eq!(trie.root(), hash_builder_root);
3885 pretty_assertions::assert_eq!(
3886 BTreeMap::from_iter(trie.updates_ref().updated_nodes.clone()),
3887 BTreeMap::from_iter(hash_builder_updates.account_nodes)
3888 );
3889 assert_eq_parallel_sparse_trie_proof_nodes(trie, hash_builder_proof_nodes);
3890 }
3891 }
3892
3893 struct SubtrieAssertion<'a> {
3895 subtrie: &'a SparseSubtrie,
3896 }
3897
3898 impl<'a> SubtrieAssertion<'a> {
3899 fn new(subtrie: &'a SparseSubtrie) -> Self {
3900 Self { subtrie }
3901 }
3902
3903 fn has_branch(self, path: &Nibbles, expected_mask_bits: &[u8]) -> Self {
3904 match self.subtrie.nodes.get(path) {
3905 Some(SparseNode::Branch { state_mask, .. }) => {
3906 for bit in expected_mask_bits {
3907 assert!(
3908 state_mask.is_bit_set(*bit),
3909 "Expected branch at {path:?} to have bit {bit} set, instead mask is: {state_mask:?}",
3910 );
3911 }
3912 }
3913 node => panic!("Expected branch node at {path:?}, found {node:?}"),
3914 }
3915 self
3916 }
3917
3918 fn has_leaf(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
3919 match self.subtrie.nodes.get(path) {
3920 Some(SparseNode::Leaf { key, .. }) => {
3921 assert_eq!(
3922 *key, *expected_key,
3923 "Expected leaf at {path:?} to have key {expected_key:?}, found {key:?}",
3924 );
3925 }
3926 node => panic!("Expected leaf node at {path:?}, found {node:?}"),
3927 }
3928 self
3929 }
3930
3931 fn has_extension(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
3932 match self.subtrie.nodes.get(path) {
3933 Some(SparseNode::Extension { key, .. }) => {
3934 assert_eq!(
3935 *key, *expected_key,
3936 "Expected extension at {path:?} to have key {expected_key:?}, found {key:?}",
3937 );
3938 }
3939 node => panic!("Expected extension node at {path:?}, found {node:?}"),
3940 }
3941 self
3942 }
3943
3944 fn has_hash(self, path: &Nibbles, expected_hash: &B256) -> Self {
3945 match self.subtrie.nodes.get(path) {
3946 Some(SparseNode::Hash(hash)) => {
3947 assert_eq!(
3948 *hash, *expected_hash,
3949 "Expected hash at {path:?} to be {expected_hash:?}, found {hash:?}",
3950 );
3951 }
3952 node => panic!("Expected hash node at {path:?}, found {node:?}"),
3953 }
3954 self
3955 }
3956
3957 fn has_value(self, path: &Nibbles, expected_value: &[u8]) -> Self {
3958 let actual = self.subtrie.inner.values.get(path);
3959 assert_eq!(
3960 actual.map(|v| v.as_slice()),
3961 Some(expected_value),
3962 "Expected value at {path:?} to be {expected_value:?}, found {actual:?}",
3963 );
3964 self
3965 }
3966
3967 fn has_no_value(self, path: &Nibbles) -> Self {
3968 let actual = self.subtrie.inner.values.get(path);
3969 assert!(actual.is_none(), "Expected no value at {path:?}, but found {actual:?}");
3970 self
3971 }
3972 }
3973
3974 fn create_leaf_node(key: impl AsRef<[u8]>, value_nonce: u64) -> TrieNode {
3975 TrieNode::Leaf(LeafNode::new(Nibbles::from_nibbles(key), encode_account_value(value_nonce)))
3976 }
3977
3978 fn create_extension_node(key: impl AsRef<[u8]>, child_hash: B256) -> TrieNode {
3979 TrieNode::Extension(ExtensionNode::new(
3980 Nibbles::from_nibbles(key),
3981 RlpNode::word_rlp(&child_hash),
3982 ))
3983 }
3984
3985 fn create_branch_node_with_children(
3986 children_indices: &[u8],
3987 child_hashes: impl IntoIterator<Item = RlpNode>,
3988 ) -> TrieNode {
3989 let mut stack = Vec::new();
3990 let mut state_mask = TrieMask::default();
3991
3992 for (&idx, hash) in children_indices.iter().zip(child_hashes.into_iter()) {
3993 state_mask.set_bit(idx);
3994 stack.push(hash);
3995 }
3996
3997 TrieNode::Branch(BranchNode::new(stack, state_mask))
3998 }
3999
4000 fn run_hash_builder(
4005 state: impl IntoIterator<Item = (Nibbles, Account)> + Clone,
4006 trie_cursor: impl TrieCursor,
4007 destroyed_accounts: B256Set,
4008 proof_targets: impl IntoIterator<Item = Nibbles>,
4009 ) -> (B256, TrieUpdates, ProofNodes, HashMap<Nibbles, TrieMask>, HashMap<Nibbles, TrieMask>)
4010 {
4011 let mut account_rlp = Vec::new();
4012
4013 let mut hash_builder = HashBuilder::default()
4014 .with_updates(true)
4015 .with_proof_retainer(ProofRetainer::from_iter(proof_targets));
4016
4017 let mut prefix_set = PrefixSetMut::default();
4018 prefix_set.extend_keys(state.clone().into_iter().map(|(nibbles, _)| nibbles));
4019 prefix_set.extend_keys(destroyed_accounts.iter().map(Nibbles::unpack));
4020 let walker = TrieWalker::<_>::state_trie(trie_cursor, prefix_set.freeze())
4021 .with_deletions_retained(true);
4022 let hashed_post_state = HashedPostState::default()
4023 .with_accounts(state.into_iter().map(|(nibbles, account)| {
4024 (nibbles.pack().into_inner().unwrap().into(), Some(account))
4025 }))
4026 .into_sorted();
4027 let mut node_iter = TrieNodeIter::state_trie(
4028 walker,
4029 HashedPostStateCursor::new_account(
4030 NoopHashedCursor::<Account>::default(),
4031 &hashed_post_state,
4032 ),
4033 );
4034
4035 while let Some(node) = node_iter.try_next().unwrap() {
4036 match node {
4037 TrieElement::Branch(branch) => {
4038 hash_builder.add_branch(branch.key, branch.value, branch.children_are_in_trie);
4039 }
4040 TrieElement::Leaf(key, account) => {
4041 let account = account.into_trie_account(EMPTY_ROOT_HASH);
4042 account.encode(&mut account_rlp);
4043
4044 hash_builder.add_leaf(Nibbles::unpack(key), &account_rlp);
4045 account_rlp.clear();
4046 }
4047 }
4048 }
4049 let root = hash_builder.root();
4050 let proof_nodes = hash_builder.take_proof_nodes();
4051 let branch_node_hash_masks = hash_builder
4052 .updated_branch_nodes
4053 .clone()
4054 .unwrap_or_default()
4055 .iter()
4056 .map(|(path, node)| (*path, node.hash_mask))
4057 .collect();
4058 let branch_node_tree_masks = hash_builder
4059 .updated_branch_nodes
4060 .clone()
4061 .unwrap_or_default()
4062 .iter()
4063 .map(|(path, node)| (*path, node.tree_mask))
4064 .collect();
4065
4066 let mut trie_updates = TrieUpdates::default();
4067 let removed_keys = node_iter.walker.take_removed_keys();
4068 trie_updates.finalize(hash_builder, removed_keys, destroyed_accounts);
4069
4070 (root, trie_updates, proof_nodes, branch_node_hash_masks, branch_node_tree_masks)
4071 }
4072
4073 fn new_test_trie<Nodes>(nodes: Nodes) -> ParallelSparseTrie
4076 where
4077 Nodes: Iterator<Item = (Nibbles, SparseNode)>,
4078 {
4079 let mut trie = ParallelSparseTrie::default().with_updates(true);
4080
4081 for (path, node) in nodes {
4082 let subtrie = trie.subtrie_for_path_mut(&path);
4083 if let SparseNode::Leaf { key, .. } = &node {
4084 let mut full_key = path;
4085 full_key.extend(key);
4086 subtrie.inner.values.insert(full_key, "LEAF VALUE".into());
4087 }
4088 subtrie.nodes.insert(path, node);
4089 }
4090 trie
4091 }
4092
4093 fn parallel_sparse_trie_nodes(
4094 sparse_trie: &ParallelSparseTrie,
4095 ) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
4096 let lower_sparse_nodes = sparse_trie
4097 .lower_subtries
4098 .iter()
4099 .filter_map(|subtrie| subtrie.as_revealed_ref())
4100 .flat_map(|subtrie| subtrie.nodes.iter());
4101
4102 let upper_sparse_nodes = sparse_trie.upper_subtrie.nodes.iter();
4103
4104 lower_sparse_nodes.chain(upper_sparse_nodes).sorted_by_key(|(path, _)| *path)
4105 }
4106
4107 fn assert_eq_parallel_sparse_trie_proof_nodes(
4110 sparse_trie: &ParallelSparseTrie,
4111 proof_nodes: ProofNodes,
4112 ) {
4113 let proof_nodes = proof_nodes
4114 .into_nodes_sorted()
4115 .into_iter()
4116 .map(|(path, node)| (path, TrieNode::decode(&mut node.as_ref()).unwrap()));
4117
4118 let all_sparse_nodes = parallel_sparse_trie_nodes(sparse_trie);
4119
4120 for ((proof_node_path, proof_node), (sparse_node_path, sparse_node)) in
4121 proof_nodes.zip(all_sparse_nodes)
4122 {
4123 assert_eq!(&proof_node_path, sparse_node_path);
4124
4125 let equals = match (&proof_node, &sparse_node) {
4126 (TrieNode::EmptyRoot, SparseNode::Empty) => true,
4128 (
4130 TrieNode::Branch(BranchNode { state_mask: proof_state_mask, .. }),
4131 SparseNode::Branch { state_mask: sparse_state_mask, .. },
4132 ) => proof_state_mask == sparse_state_mask,
4133 (
4135 TrieNode::Extension(ExtensionNode { key: proof_key, .. }),
4136 SparseNode::Extension { key: sparse_key, .. },
4137 ) |
4138 (
4140 TrieNode::Leaf(LeafNode { key: proof_key, .. }),
4141 SparseNode::Leaf { key: sparse_key, .. },
4142 ) => proof_key == sparse_key,
4143 (_, SparseNode::Empty | SparseNode::Hash(_)) => continue,
4145 _ => false,
4146 };
4147 assert!(
4148 equals,
4149 "path: {proof_node_path:?}\nproof node: {proof_node:?}\nsparse node: {sparse_node:?}"
4150 );
4151 }
4152 }
4153
4154 #[test]
4155 fn test_get_changed_subtries_empty() {
4156 let mut trie = ParallelSparseTrie::default();
4157 let mut prefix_set = PrefixSetMut::from([Nibbles::default()]).freeze();
4158
4159 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
4160 assert!(subtries.is_empty());
4161 assert_eq!(unchanged_prefix_set, PrefixSetMut::from(prefix_set.iter().copied()));
4162 }
4163
4164 #[test]
4165 fn test_get_changed_subtries() {
4166 let mut trie = ParallelSparseTrie::default();
4168 let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
4169 let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
4170 let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
4171 let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
4172 let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
4173 let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
4174
4175 trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
4177 trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
4178 trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3);
4179
4180 let unchanged_prefix_set = PrefixSetMut::from([
4181 Nibbles::from_nibbles([0x0]),
4182 Nibbles::from_nibbles([0x2, 0x0, 0x0]),
4183 ]);
4184 let mut prefix_set = PrefixSetMut::from([
4186 Nibbles::from_nibbles([0x1, 0x0, 0x0]),
4188 Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0]),
4189 ]);
4190 prefix_set.extend(unchanged_prefix_set);
4191 let mut prefix_set = prefix_set.freeze();
4192
4193 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
4195 assert_eq!(
4196 subtries
4197 .into_iter()
4198 .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
4199 (index, subtrie, prefix_set.iter().copied().collect::<Vec<_>>())
4200 })
4201 .collect::<Vec<_>>(),
4202 vec![(
4203 subtrie_2_index,
4204 subtrie_2,
4205 vec![
4206 Nibbles::from_nibbles([0x1, 0x0, 0x0]),
4207 Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0])
4208 ]
4209 )]
4210 );
4211 assert_eq!(unchanged_prefix_set, unchanged_prefix_set);
4212 assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_none());
4213
4214 assert_eq!(trie.lower_subtries[subtrie_1_index], LowerSparseSubtrie::Revealed(subtrie_1));
4216 }
4217
4218 #[test]
4219 fn test_get_changed_subtries_all() {
4220 let mut trie = ParallelSparseTrie::default();
4222 let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
4223 let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
4224 let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
4225 let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
4226 let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
4227 let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
4228
4229 trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
4231 trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
4232 trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3.clone());
4233
4234 let mut prefix_set = PrefixSetMut::all().freeze();
4236
4237 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
4239 assert_eq!(
4240 subtries
4241 .into_iter()
4242 .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
4243 (index, subtrie, prefix_set.all())
4244 })
4245 .collect::<Vec<_>>(),
4246 vec![
4247 (subtrie_1_index, subtrie_1, true),
4248 (subtrie_2_index, subtrie_2, true),
4249 (subtrie_3_index, subtrie_3, true)
4250 ]
4251 );
4252 assert_eq!(unchanged_prefix_set, PrefixSetMut::all());
4253
4254 assert!(trie.lower_subtries.iter().all(|subtrie| subtrie.as_revealed_ref().is_none()));
4255 }
4256
4257 #[test]
4258 fn test_sparse_subtrie_type() {
4259 assert_eq!(SparseSubtrieType::from_path(&Nibbles::new()), SparseSubtrieType::Upper);
4260 assert_eq!(
4261 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0])),
4262 SparseSubtrieType::Upper
4263 );
4264 assert_eq!(
4265 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15])),
4266 SparseSubtrieType::Upper
4267 );
4268 assert_eq!(
4269 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0])),
4270 SparseSubtrieType::Lower(0)
4271 );
4272 assert_eq!(
4273 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0, 0])),
4274 SparseSubtrieType::Lower(0)
4275 );
4276 assert_eq!(
4277 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1])),
4278 SparseSubtrieType::Lower(1)
4279 );
4280 assert_eq!(
4281 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1, 0])),
4282 SparseSubtrieType::Lower(1)
4283 );
4284 assert_eq!(
4285 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 15])),
4286 SparseSubtrieType::Lower(15)
4287 );
4288 assert_eq!(
4289 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 0])),
4290 SparseSubtrieType::Lower(240)
4291 );
4292 assert_eq!(
4293 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 1])),
4294 SparseSubtrieType::Lower(241)
4295 );
4296 assert_eq!(
4297 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15])),
4298 SparseSubtrieType::Lower(255)
4299 );
4300 assert_eq!(
4301 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15, 15])),
4302 SparseSubtrieType::Lower(255)
4303 );
4304 }
4305
4306 #[test]
4307 fn test_reveal_node_leaves() {
4308 let root_branch =
4311 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4312 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4313
4314 {
4315 let path = Nibbles::from_nibbles([0x1]);
4316 let node = create_leaf_node([0x2, 0x3], 42);
4317 let masks = None;
4318
4319 trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
4320
4321 assert_matches!(
4322 trie.upper_subtrie.nodes.get(&path),
4323 Some(SparseNode::Leaf { key, hash: Some(_) })
4324 if key == &Nibbles::from_nibbles([0x2, 0x3])
4325 );
4326
4327 let full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4328 assert_eq!(
4329 trie.upper_subtrie.inner.values.get(&full_path),
4330 Some(&encode_account_value(42))
4331 );
4332 }
4333
4334 let root_branch =
4339 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4340 let branch_at_1 =
4341 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xBB))]);
4342 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4343 trie.reveal_nodes(&mut [ProofTrieNode {
4344 path: Nibbles::from_nibbles([0x1]),
4345 node: branch_at_1,
4346 masks: None,
4347 }])
4348 .unwrap();
4349
4350 {
4351 let path = Nibbles::from_nibbles([0x1, 0x2]);
4352 let node = create_leaf_node([0x3, 0x4], 42);
4353 let masks = None;
4354
4355 trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
4356
4357 let idx = path_subtrie_index_unchecked(&path);
4359 assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
4360
4361 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4363 assert_eq!(lower_subtrie.path, path);
4364
4365 assert_matches!(
4366 lower_subtrie.nodes.get(&path),
4367 Some(SparseNode::Leaf { key, hash: Some(_) })
4368 if key == &Nibbles::from_nibbles([0x3, 0x4])
4369 );
4370 }
4371
4372 {
4375 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4376 let node = create_leaf_node([0x4, 0x5], 42);
4377 let masks = None;
4378
4379 trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
4380
4381 let idx = path_subtrie_index_unchecked(&path);
4383 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4384 assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2]));
4385 }
4386 }
4387
4388 #[test]
4389 fn test_reveal_node_extension_all_upper() {
4390 let path = Nibbles::new();
4391 let child_hash = B256::repeat_byte(0xab);
4392 let node = create_extension_node([0x1], child_hash);
4393 let masks = None;
4394 let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
4395
4396 assert_matches!(
4397 trie.upper_subtrie.nodes.get(&path),
4398 Some(SparseNode::Extension { key, hash: None, .. })
4399 if key == &Nibbles::from_nibbles([0x1])
4400 );
4401
4402 let child_path = Nibbles::from_nibbles([0x1]);
4404 assert_eq!(trie.upper_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
4405 }
4406
4407 #[test]
4408 fn test_reveal_node_extension_cross_level() {
4409 let path = Nibbles::new();
4410 let child_hash = B256::repeat_byte(0xcd);
4411 let node = create_extension_node([0x1, 0x2, 0x3], child_hash);
4412 let masks = None;
4413 let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
4414
4415 assert_matches!(
4417 trie.upper_subtrie.nodes.get(&path),
4418 Some(SparseNode::Extension { key, hash: None, .. })
4419 if key == &Nibbles::from_nibbles([0x1, 0x2, 0x3])
4420 );
4421
4422 let child_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4424 let idx = path_subtrie_index_unchecked(&child_path);
4425 assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
4426
4427 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4428 assert_eq!(lower_subtrie.path, child_path);
4429 assert_eq!(lower_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
4430 }
4431
4432 #[test]
4433 fn test_reveal_node_extension_cross_level_boundary() {
4434 let root_branch =
4436 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4437 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4438
4439 let path = Nibbles::from_nibbles([0x1]);
4440 let child_hash = B256::repeat_byte(0xcd);
4441 let node = create_extension_node([0x2], child_hash);
4442 let masks = None;
4443
4444 trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
4445
4446 assert_matches!(
4448 trie.upper_subtrie.nodes.get(&path),
4449 Some(SparseNode::Extension { key, hash: Some(_), .. })
4450 if key == &Nibbles::from_nibbles([0x2])
4451 );
4452
4453 let child_path = Nibbles::from_nibbles([0x1, 0x2]);
4455 let idx = path_subtrie_index_unchecked(&child_path);
4456 assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
4457
4458 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4459 assert_eq!(lower_subtrie.path, child_path);
4460 assert_eq!(lower_subtrie.nodes.get(&child_path), Some(&SparseNode::Hash(child_hash)));
4461 }
4462
4463 #[test]
4464 fn test_reveal_node_branch_all_upper() {
4465 let path = Nibbles::new();
4466 let child_hashes = [
4467 RlpNode::word_rlp(&B256::repeat_byte(0x11)),
4468 RlpNode::word_rlp(&B256::repeat_byte(0x22)),
4469 ];
4470 let node = create_branch_node_with_children(&[0x0, 0x5], child_hashes.clone());
4471 let masks = None;
4472 let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
4473
4474 assert_matches!(
4476 trie.upper_subtrie.nodes.get(&path),
4477 Some(SparseNode::Branch { state_mask, hash: None, .. })
4478 if *state_mask == 0b0000000000100001.into()
4479 );
4480
4481 let child_path_0 = Nibbles::from_nibbles([0x0]);
4483 let child_path_5 = Nibbles::from_nibbles([0x5]);
4484 assert_eq!(
4485 trie.upper_subtrie.nodes.get(&child_path_0),
4486 Some(&SparseNode::Hash(child_hashes[0].as_hash().unwrap()))
4487 );
4488 assert_eq!(
4489 trie.upper_subtrie.nodes.get(&child_path_5),
4490 Some(&SparseNode::Hash(child_hashes[1].as_hash().unwrap()))
4491 );
4492 }
4493
4494 #[test]
4495 fn test_reveal_node_branch_cross_level() {
4496 let root_branch =
4498 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4499 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4500
4501 let path = Nibbles::from_nibbles([0x1]); let child_hashes = [
4503 RlpNode::word_rlp(&B256::repeat_byte(0x33)),
4504 RlpNode::word_rlp(&B256::repeat_byte(0x44)),
4505 RlpNode::word_rlp(&B256::repeat_byte(0x55)),
4506 ];
4507 let node = create_branch_node_with_children(&[0x0, 0x7, 0xf], child_hashes.clone());
4508 let masks = None;
4509
4510 trie.reveal_nodes(&mut [ProofTrieNode { path, node, masks }]).unwrap();
4511
4512 assert_matches!(
4514 trie.upper_subtrie.nodes.get(&path),
4515 Some(SparseNode::Branch { state_mask, hash: Some(_), .. })
4516 if *state_mask == 0b1000000010000001.into()
4517 );
4518
4519 let child_paths = [
4521 Nibbles::from_nibbles([0x1, 0x0]),
4522 Nibbles::from_nibbles([0x1, 0x7]),
4523 Nibbles::from_nibbles([0x1, 0xf]),
4524 ];
4525
4526 for (i, child_path) in child_paths.iter().enumerate() {
4527 let idx = path_subtrie_index_unchecked(child_path);
4528 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4529 assert_eq!(&lower_subtrie.path, child_path);
4530 assert_eq!(
4531 lower_subtrie.nodes.get(child_path),
4532 Some(&SparseNode::Hash(child_hashes[i].as_hash().unwrap())),
4533 );
4534 }
4535 }
4536
4537 #[test]
4538 fn test_update_subtrie_hashes_prefix_set_matching() {
4539 let root_branch = create_branch_node_with_children(
4542 &[0x0, 0x3],
4543 [
4544 RlpNode::word_rlp(&B256::repeat_byte(0xAA)),
4545 RlpNode::word_rlp(&B256::repeat_byte(0xBB)),
4546 ],
4547 );
4548 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4549
4550 let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
4552 let leaf_1_path = leaf_1_full_path.slice(..2);
4553 let leaf_1_key = leaf_1_full_path.slice(2..);
4554 let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 1], vec![0; 62]].concat());
4555 let leaf_2_path = leaf_2_full_path.slice(..2);
4556 let leaf_2_key = leaf_2_full_path.slice(2..);
4557 let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 2], vec![0; 62]].concat());
4558 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), 1);
4559 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), 2);
4560
4561 let child_hashes = [
4565 RlpNode::word_rlp(&B256::repeat_byte(0x00)),
4566 RlpNode::word_rlp(&B256::repeat_byte(0x11)),
4567 ];
4568 let branch_path = Nibbles::from_nibbles([0x0]);
4569 let branch_node = create_branch_node_with_children(&[0x0, 0x1], child_hashes);
4570
4571 trie.reveal_nodes(&mut [
4573 ProofTrieNode { path: branch_path, node: branch_node, masks: None },
4574 ProofTrieNode { path: leaf_1_path, node: leaf_1, masks: None },
4575 ProofTrieNode { path: leaf_2_path, node: leaf_2, masks: None },
4576 ])
4577 .unwrap();
4578
4579 let provider = MockTrieNodeProvider::new();
4582 trie.update_leaf(leaf_3_full_path, encode_account_value(3), provider).unwrap();
4583
4584 let subtrie_1_index = SparseSubtrieType::from_path(&leaf_1_path).lower_index().unwrap();
4586 let subtrie_2_index = SparseSubtrieType::from_path(&leaf_2_path).lower_index().unwrap();
4587 let leaf_3_path = leaf_3_full_path.slice(..2);
4588 let subtrie_3_index = SparseSubtrieType::from_path(&leaf_3_path).lower_index().unwrap();
4589
4590 let mut unchanged_prefix_set = PrefixSetMut::from([
4591 Nibbles::from_nibbles([0x0]),
4592 leaf_2_full_path,
4593 Nibbles::from_nibbles([0x3, 0x0, 0x0]),
4594 ]);
4595 let mut prefix_set = PrefixSetMut::from([
4597 Nibbles::from_nibbles([0x0, 0x1, 0x0]),
4599 Nibbles::from_nibbles([0x0, 0x1, 0x1, 0x0]),
4600 ]);
4601 prefix_set.extend(unchanged_prefix_set.clone());
4602 trie.prefix_set = prefix_set;
4603
4604 trie.update_subtrie_hashes();
4606
4607 unchanged_prefix_set.insert(leaf_3_full_path);
4611
4612 assert_eq!(
4614 trie.prefix_set.clone().freeze().into_iter().collect::<Vec<_>>(),
4615 unchanged_prefix_set.freeze().into_iter().collect::<Vec<_>>()
4616 );
4617 assert!(trie.lower_subtries[subtrie_1_index].as_revealed_ref().is_some());
4619 assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_some());
4620 assert!(trie.lower_subtries[subtrie_3_index].as_revealed_ref().is_some());
4621 }
4622
4623 #[test]
4624 fn test_subtrie_update_hashes() {
4625 let mut subtrie = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
4626
4627 let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
4629 let leaf_1_path = leaf_1_full_path.slice(..5);
4630 let leaf_1_key = leaf_1_full_path.slice(5..);
4631 let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 0, 0, 0, 1], vec![0; 59]].concat());
4632 let leaf_2_path = leaf_2_full_path.slice(..5);
4633 let leaf_2_key = leaf_2_full_path.slice(5..);
4634 let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 0, 1], vec![0; 61]].concat());
4635 let leaf_3_path = leaf_3_full_path.slice(..3);
4636 let leaf_3_key = leaf_3_full_path.slice(3..);
4637
4638 let account_1 = create_account(1);
4639 let account_2 = create_account(2);
4640 let account_3 = create_account(3);
4641 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
4642 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
4643 let leaf_3 = create_leaf_node(leaf_3_key.to_vec(), account_3.nonce);
4644
4645 let branch_1_path = Nibbles::from_nibbles([0, 0, 0, 0]);
4647 let branch_1 = create_branch_node_with_children(
4648 &[0, 1],
4649 vec![
4650 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
4651 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
4652 ],
4653 );
4654
4655 let extension_path = Nibbles::from_nibbles([0, 0, 0]);
4657 let extension_key = Nibbles::from_nibbles([0]);
4658 let extension = create_extension_node(
4659 extension_key.to_vec(),
4660 RlpNode::from_rlp(&alloy_rlp::encode(&branch_1)).as_hash().unwrap(),
4661 );
4662
4663 let branch_2_path = Nibbles::from_nibbles([0, 0]);
4665 let branch_2 = create_branch_node_with_children(
4666 &[0, 1],
4667 vec![
4668 RlpNode::from_rlp(&alloy_rlp::encode(&extension)),
4669 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_3)),
4670 ],
4671 );
4672
4673 subtrie.reveal_node(branch_2_path, &branch_2, None).unwrap();
4675 subtrie.reveal_node(leaf_1_path, &leaf_1, None).unwrap();
4676 subtrie.reveal_node(extension_path, &extension, None).unwrap();
4677 subtrie.reveal_node(branch_1_path, &branch_1, None).unwrap();
4678 subtrie.reveal_node(leaf_2_path, &leaf_2, None).unwrap();
4679 subtrie.reveal_node(leaf_3_path, &leaf_3, None).unwrap();
4680
4681 let (_, _, proof_nodes, _, _) = run_hash_builder(
4683 [
4684 (leaf_1_full_path, account_1),
4685 (leaf_2_full_path, account_2),
4686 (leaf_3_full_path, account_3),
4687 ],
4688 NoopAccountTrieCursor::default(),
4689 Default::default(),
4690 [
4691 branch_1_path,
4692 extension_path,
4693 branch_2_path,
4694 leaf_1_full_path,
4695 leaf_2_full_path,
4696 leaf_3_full_path,
4697 ],
4698 );
4699
4700 subtrie.update_hashes(
4702 &mut PrefixSetMut::from([leaf_1_full_path, leaf_2_full_path, leaf_3_full_path])
4703 .freeze(),
4704 &mut None,
4705 &BranchNodeMasksMap::default(),
4706 );
4707
4708 let hash_builder_branch_1_hash =
4710 RlpNode::from_rlp(proof_nodes.get(&branch_1_path).unwrap().as_ref()).as_hash().unwrap();
4711 let subtrie_branch_1_hash = subtrie.nodes.get(&branch_1_path).unwrap().hash().unwrap();
4712 assert_eq!(hash_builder_branch_1_hash, subtrie_branch_1_hash);
4713
4714 let hash_builder_extension_hash =
4715 RlpNode::from_rlp(proof_nodes.get(&extension_path).unwrap().as_ref())
4716 .as_hash()
4717 .unwrap();
4718 let subtrie_extension_hash = subtrie.nodes.get(&extension_path).unwrap().hash().unwrap();
4719 assert_eq!(hash_builder_extension_hash, subtrie_extension_hash);
4720
4721 let hash_builder_branch_2_hash =
4722 RlpNode::from_rlp(proof_nodes.get(&branch_2_path).unwrap().as_ref()).as_hash().unwrap();
4723 let subtrie_branch_2_hash = subtrie.nodes.get(&branch_2_path).unwrap().hash().unwrap();
4724 assert_eq!(hash_builder_branch_2_hash, subtrie_branch_2_hash);
4725
4726 let subtrie_leaf_1_hash = subtrie.nodes.get(&leaf_1_path).unwrap().hash().unwrap();
4727 let hash_builder_leaf_1_hash =
4728 RlpNode::from_rlp(proof_nodes.get(&leaf_1_path).unwrap().as_ref()).as_hash().unwrap();
4729 assert_eq!(hash_builder_leaf_1_hash, subtrie_leaf_1_hash);
4730
4731 let hash_builder_leaf_2_hash =
4732 RlpNode::from_rlp(proof_nodes.get(&leaf_2_path).unwrap().as_ref()).as_hash().unwrap();
4733 let subtrie_leaf_2_hash = subtrie.nodes.get(&leaf_2_path).unwrap().hash().unwrap();
4734 assert_eq!(hash_builder_leaf_2_hash, subtrie_leaf_2_hash);
4735
4736 let hash_builder_leaf_3_hash =
4737 RlpNode::from_rlp(proof_nodes.get(&leaf_3_path).unwrap().as_ref()).as_hash().unwrap();
4738 let subtrie_leaf_3_hash = subtrie.nodes.get(&leaf_3_path).unwrap().hash().unwrap();
4739 assert_eq!(hash_builder_leaf_3_hash, subtrie_leaf_3_hash);
4740 }
4741
4742 #[test]
4743 fn test_remove_leaf_branch_becomes_extension() {
4744 let mut trie = new_test_trie(
4756 [
4757 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4758 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b1001))),
4759 (
4760 Nibbles::from_nibbles([0x5, 0x0]),
4761 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3])),
4762 ),
4763 (
4764 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
4765 SparseNode::new_branch(TrieMask::new(0b0101)),
4766 ),
4767 (
4768 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
4769 SparseNode::new_leaf(Nibbles::new()),
4770 ),
4771 (
4772 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
4773 SparseNode::new_leaf(Nibbles::new()),
4774 ),
4775 (
4776 Nibbles::from_nibbles([0x5, 0x3]),
4777 SparseNode::new_leaf(Nibbles::from_nibbles([0x7])),
4778 ),
4779 ]
4780 .into_iter(),
4781 );
4782
4783 let provider = MockTrieNodeProvider::new();
4784
4785 let leaf_full_path = Nibbles::from_nibbles([0x5, 0x3, 0x7]);
4787 trie.remove_leaf(&leaf_full_path, provider).unwrap();
4788
4789 let upper_subtrie = &trie.upper_subtrie;
4790 let lower_subtrie_50 = trie.lower_subtries[0x50].as_revealed_ref().unwrap();
4791
4792 assert_matches!(trie.lower_subtries[0x53].as_revealed_ref(), None);
4795
4796 assert_matches!(
4799 upper_subtrie.nodes.get(&Nibbles::from_nibbles([])),
4800 Some(SparseNode::Extension{ key, ..})
4801 if key == &Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])
4802 );
4803 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
4804 assert_matches!(lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0])), None);
4805 assert_matches!(
4806 lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])),
4807 Some(SparseNode::Branch{ state_mask, .. })
4808 if *state_mask == 0b0101.into()
4809 );
4810 }
4811
4812 #[test]
4813 fn test_remove_leaf_branch_becomes_leaf() {
4814 let mut trie = new_test_trie(
4822 [
4823 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0011))),
4824 (
4825 Nibbles::from_nibbles([0x0]),
4826 SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
4827 ),
4828 (
4829 Nibbles::from_nibbles([0x1]),
4830 SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
4831 ),
4832 ]
4833 .into_iter(),
4834 );
4835
4836 if let Some(updates) = trie.updates.as_mut() {
4838 updates
4839 .updated_nodes
4840 .insert(Nibbles::default(), BranchNodeCompact::new(0b11, 0, 0, vec![], None));
4841 }
4842
4843 let provider = MockTrieNodeProvider::new();
4844
4845 let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2]);
4847 trie.remove_leaf(&leaf_full_path, provider).unwrap();
4848
4849 let upper_subtrie = &trie.upper_subtrie;
4850
4851 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4853
4854 assert_matches!(
4856 upper_subtrie.nodes.get(&Nibbles::default()),
4857 Some(SparseNode::Leaf{ key, ..})
4858 if key == &Nibbles::from_nibbles([0x1, 0x3, 0x4])
4859 );
4860
4861 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
4863 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])), None);
4865
4866 let updates = trie.updates.as_ref().unwrap();
4868
4869 assert!(updates.removed_nodes.contains(&Nibbles::default()));
4871
4872 assert!(!updates.updated_nodes.contains_key(&Nibbles::default()));
4874 }
4875
4876 #[test]
4877 fn test_remove_leaf_extension_becomes_leaf() {
4878 let mut trie = new_test_trie(
4887 [
4888 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4889 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b0011))),
4890 (
4891 Nibbles::from_nibbles([0x5, 0x0]),
4892 SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
4893 ),
4894 (
4895 Nibbles::from_nibbles([0x5, 0x1]),
4896 SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
4897 ),
4898 ]
4899 .into_iter(),
4900 );
4901
4902 let provider = MockTrieNodeProvider::new();
4903
4904 let leaf_full_path = Nibbles::from_nibbles([0x5, 0x0, 0x1, 0x2]);
4906 trie.remove_leaf(&leaf_full_path, provider).unwrap();
4907
4908 let upper_subtrie = &trie.upper_subtrie;
4909
4910 assert_matches!(trie.lower_subtries[0x50].as_revealed_ref(), None);
4914 assert_matches!(trie.lower_subtries[0x51].as_revealed_ref(), None);
4915
4916 let other_leaf_full_value = Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4]);
4918 assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
4919
4920 assert_matches!(
4922 upper_subtrie.nodes.get(&Nibbles::default()),
4923 Some(SparseNode::Leaf{ key, ..})
4924 if key == &Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4])
4925 );
4926
4927 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
4929 }
4930
4931 #[test]
4932 fn test_remove_leaf_branch_on_branch() {
4933 let mut trie = new_test_trie(
4943 [
4944 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0101))),
4945 (
4946 Nibbles::from_nibbles([0x0]),
4947 SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
4948 ),
4949 (Nibbles::from_nibbles([0x2]), SparseNode::new_branch(TrieMask::new(0b0011))),
4950 (
4951 Nibbles::from_nibbles([0x2, 0x0]),
4952 SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x4])),
4953 ),
4954 (
4955 Nibbles::from_nibbles([0x2, 0x1]),
4956 SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x6])),
4957 ),
4958 ]
4959 .into_iter(),
4960 );
4961
4962 let provider = MockTrieNodeProvider::new();
4963
4964 let leaf_full_path = Nibbles::from_nibbles([0x2, 0x0, 0x3, 0x4]);
4966 trie.remove_leaf(&leaf_full_path, provider).unwrap();
4967
4968 let upper_subtrie = &trie.upper_subtrie;
4969
4970 assert_matches!(trie.lower_subtries[0x20].as_revealed_ref(), None);
4974 assert_matches!(trie.lower_subtries[0x21].as_revealed_ref(), None);
4975
4976 let other_leaf_full_value = Nibbles::from_nibbles([0x2, 0x1, 0x5, 0x6]);
4978 assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
4979
4980 assert_matches!(
4982 upper_subtrie.nodes.get(&Nibbles::default()),
4983 Some(SparseNode::Branch{ state_mask, .. })
4984 if *state_mask == 0b0101.into()
4985 );
4986
4987 assert_matches!(
4989 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x2])),
4990 Some(SparseNode::Leaf{ key, ..})
4991 if key == &Nibbles::from_nibbles([0x1, 0x5, 0x6])
4992 );
4993 }
4994
4995 #[test]
4996 fn test_remove_leaf_lower_subtrie_root_path_update() {
4997 let mut trie = new_test_trie(
5011 [
5012 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x1, 0x2, 0x3]))),
5013 (
5014 Nibbles::from_nibbles([0x1, 0x2, 0x3]),
5015 SparseNode::new_branch(TrieMask::new(0b0011000)),
5016 ),
5017 (
5018 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]),
5019 SparseNode::new_leaf(Nibbles::default()),
5020 ),
5021 (
5022 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]),
5023 SparseNode::new_ext(Nibbles::from_nibbles([0x5])),
5024 ),
5025 (
5026 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]),
5027 SparseNode::new_branch(TrieMask::new(0b0011)),
5028 ),
5029 (
5030 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x0]),
5031 SparseNode::new_leaf(Nibbles::default()),
5032 ),
5033 (
5034 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x1]),
5035 SparseNode::new_leaf(Nibbles::default()),
5036 ),
5037 ]
5038 .into_iter(),
5039 );
5040
5041 let provider = MockTrieNodeProvider::new();
5042
5043 let lower_subtrie_root_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
5045 assert_matches!(
5046 trie.lower_subtrie_for_path_mut(&lower_subtrie_root_path),
5047 Some(subtrie)
5048 if subtrie.path == lower_subtrie_root_path
5049 );
5050
5051 let leaf_full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]);
5053 trie.remove_leaf(&leaf_full_path, provider).unwrap();
5054
5055 let lower_subtrie = trie.lower_subtries[0x12].as_revealed_ref().unwrap();
5060 assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]));
5061
5062 assert_matches!(
5064 trie.upper_subtrie.nodes.get(&Nibbles::default()),
5065 Some(SparseNode::Extension { key, .. })
5066 if key == &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])
5067 );
5068
5069 assert_matches!(
5071 lower_subtrie.nodes.get(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])),
5072 Some(SparseNode::Branch { state_mask, .. })
5073 if state_mask == &TrieMask::new(0b0011)
5074 );
5075 }
5076
5077 #[test]
5078 fn test_remove_leaf_remaining_child_needs_reveal() {
5079 let mut trie = new_test_trie(
5087 [
5088 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0011))),
5089 (
5090 Nibbles::from_nibbles([0x0]),
5091 SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2])),
5092 ),
5093 (Nibbles::from_nibbles([0x1]), SparseNode::Hash(B256::repeat_byte(0xab))),
5094 ]
5095 .into_iter(),
5096 );
5097
5098 let mut provider = MockTrieNodeProvider::new();
5100 let revealed_leaf = create_leaf_node([0x3, 0x4], 42);
5101 let mut encoded = Vec::new();
5102 revealed_leaf.encode(&mut encoded);
5103 provider.add_revealed_node(
5104 Nibbles::from_nibbles([0x1]),
5105 RevealedNode { node: encoded.into(), tree_mask: None, hash_mask: None },
5106 );
5107
5108 let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2]);
5110 trie.remove_leaf(&leaf_full_path, provider).unwrap();
5111
5112 let upper_subtrie = &trie.upper_subtrie;
5113
5114 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
5116
5117 assert_matches!(
5119 upper_subtrie.nodes.get(&Nibbles::default()),
5120 Some(SparseNode::Leaf{ key, ..})
5121 if key == &Nibbles::from_nibbles([0x1, 0x3, 0x4])
5122 );
5123
5124 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
5126 }
5127
5128 #[test]
5129 fn test_remove_leaf_root() {
5130 let mut trie = new_test_trie(core::iter::once((
5136 Nibbles::default(),
5137 SparseNode::new_leaf(Nibbles::from_nibbles([0x1, 0x2, 0x3])),
5138 )));
5139
5140 let provider = MockTrieNodeProvider::new();
5141
5142 let leaf_full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
5144 trie.remove_leaf(&leaf_full_path, provider).unwrap();
5145
5146 let upper_subtrie = &trie.upper_subtrie;
5147
5148 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
5150
5151 assert_matches!(upper_subtrie.nodes.get(&Nibbles::default()), Some(SparseNode::Empty));
5153 }
5154
5155 #[test]
5156 fn test_remove_leaf_unsets_hash_along_path() {
5157 let mut trie = new_test_trie(
5172 [
5173 (
5174 Nibbles::default(),
5175 SparseNode::Branch {
5176 state_mask: TrieMask::new(0b0011),
5177 hash: Some(B256::repeat_byte(0x10)),
5178 store_in_db_trie: None,
5179 },
5180 ),
5181 (
5182 Nibbles::from_nibbles([0x0]),
5183 SparseNode::Extension {
5184 key: Nibbles::from_nibbles([0x1]),
5185 hash: Some(B256::repeat_byte(0x20)),
5186 store_in_db_trie: None,
5187 },
5188 ),
5189 (
5190 Nibbles::from_nibbles([0x0, 0x1]),
5191 SparseNode::Branch {
5192 state_mask: TrieMask::new(0b11100),
5193 hash: Some(B256::repeat_byte(0x30)),
5194 store_in_db_trie: None,
5195 },
5196 ),
5197 (
5198 Nibbles::from_nibbles([0x0, 0x1, 0x2]),
5199 SparseNode::Leaf {
5200 key: Nibbles::from_nibbles([0x3, 0x4]),
5201 hash: Some(B256::repeat_byte(0x40)),
5202 },
5203 ),
5204 (
5205 Nibbles::from_nibbles([0x0, 0x1, 0x3]),
5206 SparseNode::Leaf {
5207 key: Nibbles::from_nibbles([0x5, 0x6]),
5208 hash: Some(B256::repeat_byte(0x50)),
5209 },
5210 ),
5211 (
5212 Nibbles::from_nibbles([0x0, 0x1, 0x4]),
5213 SparseNode::Leaf {
5214 key: Nibbles::from_nibbles([0x6, 0x7]),
5215 hash: Some(B256::repeat_byte(0x60)),
5216 },
5217 ),
5218 (
5219 Nibbles::from_nibbles([0x1]),
5220 SparseNode::Leaf {
5221 key: Nibbles::from_nibbles([0x7, 0x8]),
5222 hash: Some(B256::repeat_byte(0x70)),
5223 },
5224 ),
5225 ]
5226 .into_iter(),
5227 );
5228
5229 let provider = MockTrieNodeProvider::new();
5230
5231 trie.remove_leaf(&Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4, 0xF]), &provider)
5233 .unwrap();
5234 for (path, node) in trie.all_nodes() {
5235 assert!(node.hash().is_some(), "path {path:?} should still have a hash");
5236 }
5237
5238 let leaf_full_path = Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4]);
5240 trie.remove_leaf(&leaf_full_path, &provider).unwrap();
5241
5242 let upper_subtrie = &trie.upper_subtrie;
5243 let lower_subtrie_10 = trie.lower_subtries[0x01].as_revealed_ref().unwrap();
5244
5245 assert_matches!(
5247 upper_subtrie.nodes.get(&Nibbles::default()),
5248 Some(SparseNode::Branch { hash: None, .. })
5249 );
5250 assert_matches!(
5251 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])),
5252 Some(SparseNode::Extension { hash: None, .. })
5253 );
5254 assert_matches!(
5255 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1])),
5256 Some(SparseNode::Branch { hash: None, .. })
5257 );
5258
5259 assert_matches!(
5261 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])),
5262 Some(SparseNode::Leaf { hash: Some(_), .. })
5263 );
5264 assert_matches!(
5265 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x3])),
5266 Some(SparseNode::Leaf { hash: Some(_), .. })
5267 );
5268 assert_matches!(
5269 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x4])),
5270 Some(SparseNode::Leaf { hash: Some(_), .. })
5271 );
5272 }
5273
5274 #[test]
5275 fn test_remove_leaf_remaining_extension_node_child_is_revealed() {
5276 let branch_path = Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7]);
5277 let removed_branch_path = Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2]);
5278
5279 let mut nodes = vec![
5281 ProofTrieNode {
5283 path: branch_path,
5284 node: {
5285 TrieNode::Branch(BranchNode::new(
5286 vec![
5287 RlpNode::word_rlp(&B256::from(hex!(
5288 "dede882d52f0e0eddfb5b89293a10c87468b4a73acd0d4ae550054a92353f6d5"
5289 ))),
5290 RlpNode::word_rlp(&B256::from(hex!(
5291 "8746f18e465e2eed16117306b6f2eef30bc9d2978aee4a7838255e39c41a3222"
5292 ))),
5293 RlpNode::word_rlp(&B256::from(hex!(
5294 "35a4ea861548af5f0262a9b6d619b4fc88fce6531cbd004eab1530a73f34bbb1"
5295 ))),
5296 RlpNode::word_rlp(&B256::from(hex!(
5297 "47d5c2bf9eea5c1ee027e4740c2b86159074a27d52fd2f6a8a8c86c77e48006f"
5298 ))),
5299 RlpNode::word_rlp(&B256::from(hex!(
5300 "eb76a359b216e1d86b1f2803692a9fe8c3d3f97a9fe6a82b396e30344febc0c1"
5301 ))),
5302 RlpNode::word_rlp(&B256::from(hex!(
5303 "437656f2697f167b23e33cb94acc8550128cfd647fc1579d61e982cb7616b8bc"
5304 ))),
5305 RlpNode::word_rlp(&B256::from(hex!(
5306 "45a1ac2faf15ea8a4da6f921475974e0379f39c3d08166242255a567fa88ce6c"
5307 ))),
5308 RlpNode::word_rlp(&B256::from(hex!(
5309 "7dbb299d714d3dfa593f53bc1b8c66d5c401c30a0b5587b01254a56330361395"
5310 ))),
5311 RlpNode::word_rlp(&B256::from(hex!(
5312 "ae407eb14a74ed951c9949c1867fb9ee9ba5d5b7e03769eaf3f29c687d080429"
5313 ))),
5314 RlpNode::word_rlp(&B256::from(hex!(
5315 "768d0fe1003f0e85d3bc76e4a1fa0827f63b10ca9bca52d56c2b1cceb8eb8b08"
5316 ))),
5317 RlpNode::word_rlp(&B256::from(hex!(
5318 "e5127935143493d5094f4da6e4f7f5a0f62d524fbb61e7bb9fb63d8a166db0f3"
5319 ))),
5320 RlpNode::word_rlp(&B256::from(hex!(
5321 "7f3698297308664fbc1b9e2c41d097fbd57d8f364c394f6ad7c71b10291fbf42"
5322 ))),
5323 RlpNode::word_rlp(&B256::from(hex!(
5324 "4a2bc7e19cec63cb5ef5754add0208959b50bcc79f13a22a370f77b277dbe6db"
5325 ))),
5326 RlpNode::word_rlp(&B256::from(hex!(
5327 "40764b8c48de59258e62a3371909a107e76e1b5e847cfa94dbc857e9fd205103"
5328 ))),
5329 RlpNode::word_rlp(&B256::from(hex!(
5330 "2985dca29a7616920d95c43ab62eb013a40e6a0c88c284471e4c3bd22f3b9b25"
5331 ))),
5332 RlpNode::word_rlp(&B256::from(hex!(
5333 "1b6511f7a385e79477239f7dd4a49f52082ecac05aa5bd0de18b1d55fe69d10c"
5334 ))),
5335 ],
5336 TrieMask::new(0b1111111111111111),
5337 ))
5338 },
5339 masks: Some(BranchNodeMasks {
5340 hash_mask: TrieMask::new(0b1111111111111111),
5341 tree_mask: TrieMask::new(0b0011110100100101),
5342 }),
5343 },
5344 ProofTrieNode {
5346 path: removed_branch_path,
5347 node: {
5348 let stack = vec![
5349 RlpNode::word_rlp(&B256::from(hex!(
5350 "15fd4993a41feff1af3b629b32572ab05acddd97c681d82ec2eb89c8a8e3ab9e"
5351 ))),
5352 RlpNode::word_rlp(&B256::from(hex!(
5353 "a272b0b94ced4e6ec7adb41719850cf4a167ad8711d0dda6a810d129258a0d94"
5354 ))),
5355 ];
5356 let branch_node = BranchNode::new(stack, TrieMask::new(0b0001000000000100));
5357 TrieNode::Branch(branch_node)
5358 },
5359 masks: Some(BranchNodeMasks {
5360 hash_mask: TrieMask::new(0b0000000000000000),
5361 tree_mask: TrieMask::new(0b0000000000000100),
5362 }),
5363 },
5364 ProofTrieNode {
5366 path: Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0x2]),
5367 node: {
5368 let extension_node = ExtensionNode::new(
5369 Nibbles::from_nibbles([0x6]),
5370 RlpNode::word_rlp(&B256::from(hex!(
5371 "56fab2b106a97eae9c7197f86d03bca292da6e0ac725b783082f7d950cc4e0fc"
5372 ))),
5373 );
5374 TrieNode::Extension(extension_node)
5375 },
5376 masks: None,
5377 },
5378 ProofTrieNode {
5380 path: Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0xc]),
5381 node: {
5382 let leaf_node = LeafNode::new(
5383 Nibbles::from_nibbles([
5384 0x0, 0x7, 0x7, 0xf, 0x8, 0x6, 0x6, 0x1, 0x3, 0x0, 0x8, 0x8, 0xd, 0xf,
5385 0xc, 0xa, 0xe, 0x6, 0x4, 0x8, 0xa, 0xb, 0xe, 0x8, 0x3, 0x1, 0xf, 0xa,
5386 0xd, 0xc, 0xa, 0x5, 0x5, 0xa, 0xd, 0x4, 0x3, 0xa, 0xb, 0x1, 0x6, 0x5,
5387 0xd, 0x1, 0x6, 0x8, 0x0, 0xd, 0xd, 0x5, 0x6, 0x7, 0xb, 0x5, 0xd, 0x6,
5388 ]),
5389 hex::decode("8468d3971d").unwrap(),
5390 );
5391 TrieNode::Leaf(leaf_node)
5392 },
5393 masks: None,
5394 },
5395 ];
5396
5397 let mut trie = ParallelSparseTrie::from_root(
5399 TrieNode::Extension(ExtensionNode::new(
5400 Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7]),
5401 RlpNode::word_rlp(&B256::from(hex!(
5402 "56fab2b106a97eae9c7197f86d03bca292da6e0ac725b783082f7d950cc4e0fc"
5403 ))),
5404 )),
5405 None,
5406 true,
5407 )
5408 .unwrap();
5409
5410 trie.reveal_nodes(&mut nodes).unwrap();
5412
5413 let leaf_key = Nibbles::from_nibbles([
5415 0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0xc, 0x0, 0x7, 0x7, 0xf, 0x8, 0x6, 0x6, 0x1, 0x3,
5416 0x0, 0x8, 0x8, 0xd, 0xf, 0xc, 0xa, 0xe, 0x6, 0x4, 0x8, 0xa, 0xb, 0xe, 0x8, 0x3, 0x1,
5417 0xf, 0xa, 0xd, 0xc, 0xa, 0x5, 0x5, 0xa, 0xd, 0x4, 0x3, 0xa, 0xb, 0x1, 0x6, 0x5, 0xd,
5418 0x1, 0x6, 0x8, 0x0, 0xd, 0xd, 0x5, 0x6, 0x7, 0xb, 0x5, 0xd, 0x6,
5419 ]);
5420
5421 let mut provider = MockTrieNodeProvider::new();
5422 let revealed_branch = create_branch_node_with_children(&[], []);
5423 let mut encoded = Vec::new();
5424 revealed_branch.encode(&mut encoded);
5425 provider.add_revealed_node(
5426 Nibbles::from_nibbles([0x4, 0xf, 0x8, 0x8, 0x0, 0x7, 0x2, 0x2, 0x6]),
5427 RevealedNode {
5428 node: encoded.into(),
5429 tree_mask: None,
5430 hash_mask: Some(TrieMask::new(0b1111)),
5432 },
5433 );
5434
5435 trie.remove_leaf(&leaf_key, provider).unwrap();
5436
5437 trie.root();
5439
5440 let updates = trie.take_updates();
5442 assert_eq!(
5443 updates.removed_nodes.into_iter().collect::<Vec<_>>(),
5444 vec![removed_branch_path]
5445 );
5446 assert_eq!(updates.updated_nodes.len(), 1);
5447 let updated_node = updates.updated_nodes.get(&branch_path).unwrap();
5448
5449 assert_eq!(updated_node.tree_mask, TrieMask::new(0b011110100100101),)
5451 }
5452
5453 #[test]
5454 fn test_parallel_sparse_trie_root() {
5455 let extension_path = Nibbles::new();
5458 let extension_key = Nibbles::from_nibbles([0x2]);
5459
5460 let branch_path = Nibbles::from_nibbles([0x2]);
5462
5463 let leaf_1_path = Nibbles::from_nibbles([0x2, 0x0]);
5465 let leaf_1_key = Nibbles::from_nibbles(vec![0; 62]); let leaf_1_full_path = Nibbles::from_nibbles([vec![0x2, 0x0], vec![0; 62]].concat());
5467
5468 let leaf_2_path = Nibbles::from_nibbles([0x2, 0x1]);
5469 let leaf_2_key = Nibbles::from_nibbles(vec![0; 62]); let leaf_2_full_path = Nibbles::from_nibbles([vec![0x2, 0x1], vec![0; 62]].concat());
5471
5472 let account_1 = create_account(1);
5474 let account_2 = create_account(2);
5475
5476 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
5478 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
5479
5480 let branch = create_branch_node_with_children(
5482 &[0, 1],
5483 vec![
5484 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
5485 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
5486 ],
5487 );
5488
5489 let extension = create_extension_node(
5491 extension_key.to_vec(),
5492 RlpNode::from_rlp(&alloy_rlp::encode(&branch)).as_hash().unwrap(),
5493 );
5494
5495 let mut trie = ParallelSparseTrie::from_root(extension, None, true).unwrap();
5497 trie.reveal_nodes(&mut [
5498 ProofTrieNode { path: branch_path, node: branch, masks: None },
5499 ProofTrieNode { path: leaf_1_path, node: leaf_1, masks: None },
5500 ProofTrieNode { path: leaf_2_path, node: leaf_2, masks: None },
5501 ])
5502 .unwrap();
5503
5504 trie.upper_subtrie.nodes.get_mut(&extension_path).unwrap().set_hash(None);
5507 trie.upper_subtrie.nodes.get_mut(&branch_path).unwrap().set_hash(None);
5508
5509 let leaf_1_subtrie_idx = path_subtrie_index_unchecked(&leaf_1_path);
5511 let leaf_2_subtrie_idx = path_subtrie_index_unchecked(&leaf_2_path);
5512
5513 trie.lower_subtries[leaf_1_subtrie_idx]
5514 .as_revealed_mut()
5515 .unwrap()
5516 .nodes
5517 .get_mut(&leaf_1_path)
5518 .unwrap()
5519 .set_hash(None);
5520 trie.lower_subtries[leaf_2_subtrie_idx]
5521 .as_revealed_mut()
5522 .unwrap()
5523 .nodes
5524 .get_mut(&leaf_2_path)
5525 .unwrap()
5526 .set_hash(None);
5527
5528 trie.prefix_set.insert(leaf_1_full_path);
5530 trie.prefix_set.insert(leaf_2_full_path);
5531
5532 let root = trie.root();
5534
5535 let (hash_builder_root, _, _proof_nodes, _, _) = run_hash_builder(
5537 [(leaf_1_full_path, account_1), (leaf_2_full_path, account_2)],
5538 NoopAccountTrieCursor::default(),
5539 Default::default(),
5540 [extension_path, branch_path, leaf_1_full_path, leaf_2_full_path],
5541 );
5542
5543 assert_eq!(root, hash_builder_root);
5545
5546 let leaf_1_subtrie = trie.lower_subtries[leaf_1_subtrie_idx].as_revealed_ref().unwrap();
5548 let leaf_2_subtrie = trie.lower_subtries[leaf_2_subtrie_idx].as_revealed_ref().unwrap();
5549 assert!(trie.upper_subtrie.nodes.get(&extension_path).unwrap().hash().is_some());
5550 assert!(trie.upper_subtrie.nodes.get(&branch_path).unwrap().hash().is_some());
5551 assert!(leaf_1_subtrie.nodes.get(&leaf_1_path).unwrap().hash().is_some());
5552 assert!(leaf_2_subtrie.nodes.get(&leaf_2_path).unwrap().hash().is_some());
5553 }
5554
5555 #[test]
5556 fn sparse_trie_empty_update_one() {
5557 let ctx = ParallelSparseTrieTestContext;
5558
5559 let key = Nibbles::unpack(B256::with_last_byte(42));
5560 let value = || Account::default();
5561 let value_encoded = || {
5562 let mut account_rlp = Vec::new();
5563 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5564 account_rlp
5565 };
5566
5567 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5568 run_hash_builder(
5569 [(key, value())],
5570 NoopAccountTrieCursor::default(),
5571 Default::default(),
5572 [key],
5573 );
5574
5575 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5576 ctx.update_leaves(&mut sparse, [(key, value_encoded())]);
5577 ctx.assert_with_hash_builder(
5578 &mut sparse,
5579 hash_builder_root,
5580 hash_builder_updates,
5581 hash_builder_proof_nodes,
5582 );
5583 }
5584
5585 #[test]
5586 fn sparse_trie_empty_update_multiple_lower_nibbles() {
5587 let ctx = ParallelSparseTrieTestContext;
5588
5589 let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::<Vec<_>>();
5590 let value = || Account::default();
5591 let value_encoded = || {
5592 let mut account_rlp = Vec::new();
5593 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5594 account_rlp
5595 };
5596
5597 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5598 run_hash_builder(
5599 paths.iter().copied().zip(core::iter::repeat_with(value)),
5600 NoopAccountTrieCursor::default(),
5601 Default::default(),
5602 paths.clone(),
5603 );
5604
5605 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5606 ctx.update_leaves(
5607 &mut sparse,
5608 paths.into_iter().zip(core::iter::repeat_with(value_encoded)),
5609 );
5610
5611 ctx.assert_with_hash_builder(
5612 &mut sparse,
5613 hash_builder_root,
5614 hash_builder_updates,
5615 hash_builder_proof_nodes,
5616 );
5617 }
5618
5619 #[test]
5620 fn sparse_trie_empty_update_multiple_upper_nibbles() {
5621 let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
5622 let value = || Account::default();
5623 let value_encoded = || {
5624 let mut account_rlp = Vec::new();
5625 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5626 account_rlp
5627 };
5628
5629 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5630 run_hash_builder(
5631 paths.iter().copied().zip(core::iter::repeat_with(value)),
5632 NoopAccountTrieCursor::default(),
5633 Default::default(),
5634 paths.clone(),
5635 );
5636
5637 let provider = DefaultTrieNodeProvider;
5638 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5639 for path in &paths {
5640 sparse.update_leaf(*path, value_encoded(), &provider).unwrap();
5641 }
5642 let sparse_root = sparse.root();
5643 let sparse_updates = sparse.take_updates();
5644
5645 assert_eq!(sparse_root, hash_builder_root);
5646 assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
5647 assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
5648 }
5649
5650 #[test]
5651 fn sparse_trie_empty_update_multiple() {
5652 let ctx = ParallelSparseTrieTestContext;
5653
5654 let paths = (0..=255)
5655 .map(|b| {
5656 Nibbles::unpack(if b % 2 == 0 {
5657 B256::repeat_byte(b)
5658 } else {
5659 B256::with_last_byte(b)
5660 })
5661 })
5662 .collect::<Vec<_>>();
5663 let value = || Account::default();
5664 let value_encoded = || {
5665 let mut account_rlp = Vec::new();
5666 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5667 account_rlp
5668 };
5669
5670 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5671 run_hash_builder(
5672 paths.iter().sorted_unstable().copied().zip(core::iter::repeat_with(value)),
5673 NoopAccountTrieCursor::default(),
5674 Default::default(),
5675 paths.clone(),
5676 );
5677
5678 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5679 ctx.update_leaves(
5680 &mut sparse,
5681 paths.iter().copied().zip(core::iter::repeat_with(value_encoded)),
5682 );
5683 ctx.assert_with_hash_builder(
5684 &mut sparse,
5685 hash_builder_root,
5686 hash_builder_updates,
5687 hash_builder_proof_nodes,
5688 );
5689 }
5690
5691 #[test]
5692 fn sparse_trie_empty_update_repeated() {
5693 let ctx = ParallelSparseTrieTestContext;
5694
5695 let paths = (0..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
5696 let old_value = Account { nonce: 1, ..Default::default() };
5697 let old_value_encoded = {
5698 let mut account_rlp = Vec::new();
5699 old_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5700 account_rlp
5701 };
5702 let new_value = Account { nonce: 2, ..Default::default() };
5703 let new_value_encoded = {
5704 let mut account_rlp = Vec::new();
5705 new_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5706 account_rlp
5707 };
5708
5709 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5710 run_hash_builder(
5711 paths.iter().copied().zip(core::iter::repeat_with(|| old_value)),
5712 NoopAccountTrieCursor::default(),
5713 Default::default(),
5714 paths.clone(),
5715 );
5716
5717 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5718 ctx.update_leaves(
5719 &mut sparse,
5720 paths.iter().copied().zip(core::iter::repeat(old_value_encoded)),
5721 );
5722 ctx.assert_with_hash_builder(
5723 &mut sparse,
5724 hash_builder_root,
5725 hash_builder_updates,
5726 hash_builder_proof_nodes,
5727 );
5728
5729 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5730 run_hash_builder(
5731 paths.iter().copied().zip(core::iter::repeat(new_value)),
5732 NoopAccountTrieCursor::default(),
5733 Default::default(),
5734 paths.clone(),
5735 );
5736
5737 ctx.update_leaves(
5738 &mut sparse,
5739 paths.iter().copied().zip(core::iter::repeat(new_value_encoded)),
5740 );
5741 ctx.assert_with_hash_builder(
5742 &mut sparse,
5743 hash_builder_root,
5744 hash_builder_updates,
5745 hash_builder_proof_nodes,
5746 );
5747 }
5748
5749 #[test]
5750 fn sparse_trie_remove_leaf() {
5751 let ctx = ParallelSparseTrieTestContext;
5752 let provider = DefaultTrieNodeProvider;
5753 let mut sparse = ParallelSparseTrie::default();
5754
5755 let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
5756
5757 ctx.update_leaves(
5758 &mut sparse,
5759 [
5760 (Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), value.clone()),
5761 (Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), value.clone()),
5762 (Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), value.clone()),
5763 (Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), value.clone()),
5764 (Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), value.clone()),
5765 (Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), value),
5766 ],
5767 );
5768
5769 pretty_assertions::assert_eq!(
5782 parallel_sparse_trie_nodes(&sparse)
5783 .into_iter()
5784 .map(|(k, v)| (*k, v.clone()))
5785 .collect::<BTreeMap<_, _>>(),
5786 BTreeMap::from_iter([
5787 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5788 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1101.into())),
5789 (
5790 Nibbles::from_nibbles([0x5, 0x0]),
5791 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
5792 ),
5793 (
5794 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
5795 SparseNode::new_branch(0b1010.into())
5796 ),
5797 (
5798 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
5799 SparseNode::new_leaf(Nibbles::default())
5800 ),
5801 (
5802 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
5803 SparseNode::new_leaf(Nibbles::default())
5804 ),
5805 (
5806 Nibbles::from_nibbles([0x5, 0x2]),
5807 SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x1, 0x3]))
5808 ),
5809 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
5810 (
5811 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5812 SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
5813 ),
5814 (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
5815 (
5816 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5817 SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
5818 ),
5819 (
5820 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5821 SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
5822 )
5823 ])
5824 );
5825
5826 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3]), &provider).unwrap();
5827
5828 pretty_assertions::assert_eq!(
5840 parallel_sparse_trie_nodes(&sparse)
5841 .into_iter()
5842 .map(|(k, v)| (*k, v.clone()))
5843 .collect::<BTreeMap<_, _>>(),
5844 BTreeMap::from_iter([
5845 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5846 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
5847 (
5848 Nibbles::from_nibbles([0x5, 0x0]),
5849 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
5850 ),
5851 (
5852 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
5853 SparseNode::new_branch(0b1010.into())
5854 ),
5855 (
5856 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
5857 SparseNode::new_leaf(Nibbles::default())
5858 ),
5859 (
5860 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
5861 SparseNode::new_leaf(Nibbles::default())
5862 ),
5863 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
5864 (
5865 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5866 SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
5867 ),
5868 (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
5869 (
5870 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5871 SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
5872 ),
5873 (
5874 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5875 SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
5876 )
5877 ])
5878 );
5879
5880 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]), &provider).unwrap();
5881
5882 pretty_assertions::assert_eq!(
5891 parallel_sparse_trie_nodes(&sparse)
5892 .into_iter()
5893 .map(|(k, v)| (*k, v.clone()))
5894 .collect::<BTreeMap<_, _>>(),
5895 BTreeMap::from_iter([
5896 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5897 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
5898 (
5899 Nibbles::from_nibbles([0x5, 0x0]),
5900 SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
5901 ),
5902 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into())),
5903 (
5904 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5905 SparseNode::new_leaf(Nibbles::from_nibbles([0x0, 0x2]))
5906 ),
5907 (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
5908 (
5909 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5910 SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
5911 ),
5912 (
5913 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5914 SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
5915 )
5916 ])
5917 );
5918
5919 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2]), &provider).unwrap();
5920
5921 pretty_assertions::assert_eq!(
5928 parallel_sparse_trie_nodes(&sparse)
5929 .into_iter()
5930 .map(|(k, v)| (*k, v.clone()))
5931 .collect::<BTreeMap<_, _>>(),
5932 BTreeMap::from_iter([
5933 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5934 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
5935 (
5936 Nibbles::from_nibbles([0x5, 0x0]),
5937 SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
5938 ),
5939 (
5940 Nibbles::from_nibbles([0x5, 0x3]),
5941 SparseNode::new_ext(Nibbles::from_nibbles([0x3]))
5942 ),
5943 (Nibbles::from_nibbles([0x5, 0x3, 0x3]), SparseNode::new_branch(0b0101.into())),
5944 (
5945 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5946 SparseNode::new_leaf(Nibbles::from_nibbles([0x2]))
5947 ),
5948 (
5949 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5950 SparseNode::new_leaf(Nibbles::from_nibbles([0x0]))
5951 )
5952 ])
5953 );
5954
5955 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0]), &provider).unwrap();
5956
5957 pretty_assertions::assert_eq!(
5962 parallel_sparse_trie_nodes(&sparse)
5963 .into_iter()
5964 .map(|(k, v)| (*k, v.clone()))
5965 .collect::<BTreeMap<_, _>>(),
5966 BTreeMap::from_iter([
5967 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5968 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into())),
5969 (
5970 Nibbles::from_nibbles([0x5, 0x0]),
5971 SparseNode::new_leaf(Nibbles::from_nibbles([0x2, 0x3, 0x3]))
5972 ),
5973 (
5974 Nibbles::from_nibbles([0x5, 0x3]),
5975 SparseNode::new_leaf(Nibbles::from_nibbles([0x3, 0x0, 0x2]))
5976 ),
5977 ])
5978 );
5979
5980 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]), &provider).unwrap();
5981
5982 pretty_assertions::assert_eq!(
5984 parallel_sparse_trie_nodes(&sparse)
5985 .into_iter()
5986 .map(|(k, v)| (*k, v.clone()))
5987 .collect::<BTreeMap<_, _>>(),
5988 BTreeMap::from_iter([(
5989 Nibbles::default(),
5990 SparseNode::new_leaf(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]))
5991 ),])
5992 );
5993
5994 sparse.remove_leaf(&Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2]), &provider).unwrap();
5995
5996 pretty_assertions::assert_eq!(
5998 parallel_sparse_trie_nodes(&sparse)
5999 .into_iter()
6000 .map(|(k, v)| (*k, v.clone()))
6001 .collect::<BTreeMap<_, _>>(),
6002 BTreeMap::from_iter([(Nibbles::default(), SparseNode::Empty)])
6003 );
6004 }
6005
6006 #[test]
6007 fn sparse_trie_remove_leaf_blinded() {
6008 let leaf = LeafNode::new(
6009 Nibbles::default(),
6010 alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
6011 );
6012 let branch = TrieNode::Branch(BranchNode::new(
6013 vec![
6014 RlpNode::word_rlp(&B256::repeat_byte(1)),
6015 RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
6016 ],
6017 TrieMask::new(0b11),
6018 ));
6019
6020 let provider = DefaultTrieNodeProvider;
6021 let mut sparse = ParallelSparseTrie::from_root(
6022 branch.clone(),
6023 Some(BranchNodeMasks {
6024 hash_mask: TrieMask::new(0b01),
6025 tree_mask: TrieMask::default(),
6026 }),
6027 false,
6028 )
6029 .unwrap();
6030
6031 sparse
6037 .reveal_nodes(&mut [
6038 ProofTrieNode {
6039 path: Nibbles::default(),
6040 node: branch,
6041 masks: Some(BranchNodeMasks {
6042 hash_mask: TrieMask::default(),
6043 tree_mask: TrieMask::new(0b01),
6044 }),
6045 },
6046 ProofTrieNode {
6047 path: Nibbles::from_nibbles([0x1]),
6048 node: TrieNode::Leaf(leaf),
6049 masks: None,
6050 },
6051 ])
6052 .unwrap();
6053
6054 assert_matches!(
6056 sparse.remove_leaf(&Nibbles::from_nibbles([0x0]), &provider).map_err(|e| e.into_kind()),
6057 Err(SparseTrieErrorKind::BlindedNode { path, hash }) if path == Nibbles::from_nibbles([0x0]) && hash == B256::repeat_byte(1)
6058 );
6059 }
6060
6061 #[test]
6062 fn sparse_trie_remove_leaf_non_existent() {
6063 let leaf = LeafNode::new(
6064 Nibbles::default(),
6065 alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
6066 );
6067 let branch = TrieNode::Branch(BranchNode::new(
6068 vec![
6069 RlpNode::word_rlp(&B256::repeat_byte(1)),
6070 RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
6071 ],
6072 TrieMask::new(0b11),
6073 ));
6074
6075 let provider = DefaultTrieNodeProvider;
6076 let mut sparse = ParallelSparseTrie::from_root(
6077 branch.clone(),
6078 Some(BranchNodeMasks {
6079 hash_mask: TrieMask::new(0b01),
6080 tree_mask: TrieMask::default(),
6081 }),
6082 false,
6083 )
6084 .unwrap();
6085
6086 sparse
6092 .reveal_nodes(&mut [
6093 ProofTrieNode {
6094 path: Nibbles::default(),
6095 node: branch,
6096 masks: Some(BranchNodeMasks {
6097 hash_mask: TrieMask::default(),
6098 tree_mask: TrieMask::new(0b01),
6099 }),
6100 },
6101 ProofTrieNode {
6102 path: Nibbles::from_nibbles([0x1]),
6103 node: TrieNode::Leaf(leaf),
6104 masks: None,
6105 },
6106 ])
6107 .unwrap();
6108
6109 let sparse_old = sparse.clone();
6111 assert_matches!(sparse.remove_leaf(&Nibbles::from_nibbles([0x2]), &provider), Ok(()));
6112 assert_eq!(sparse, sparse_old);
6113 }
6114
6115 #[test]
6116 fn sparse_trie_fuzz() {
6117 const KEY_NIBBLES_LEN: usize = 3;
6121
6122 fn test(updates: Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)>) {
6123 {
6124 let mut state = BTreeMap::default();
6125 let default_provider = DefaultTrieNodeProvider;
6126 let provider_factory = create_test_provider_factory();
6127 let mut sparse = ParallelSparseTrie::default().with_updates(true);
6128
6129 for (update, keys_to_delete) in updates {
6130 for (key, account) in update.clone() {
6132 let account = account.into_trie_account(EMPTY_ROOT_HASH);
6133 let mut account_rlp = Vec::new();
6134 account.encode(&mut account_rlp);
6135 sparse.update_leaf(key, account_rlp, &default_provider).unwrap();
6136 }
6137 let mut updated_sparse = sparse.clone();
6141 let sparse_root = updated_sparse.root();
6142 let sparse_updates = updated_sparse.take_updates();
6143
6144 state.extend(update);
6146 let provider = provider_factory.provider().unwrap();
6147 let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
6148 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
6149 run_hash_builder(
6150 state.clone(),
6151 trie_cursor.account_trie_cursor().unwrap(),
6152 Default::default(),
6153 state.keys().copied(),
6154 );
6155
6156 let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
6158
6159 let provider_rw = provider_factory.provider_rw().unwrap();
6161 provider_rw.write_trie_updates(hash_builder_updates).unwrap();
6162 provider_rw.commit().unwrap();
6163
6164 assert_eq!(sparse_root, hash_builder_root);
6166 pretty_assertions::assert_eq!(
6168 BTreeMap::from_iter(sparse_updates.updated_nodes),
6169 BTreeMap::from_iter(hash_builder_account_nodes)
6170 );
6171 assert_eq_parallel_sparse_trie_proof_nodes(
6173 &updated_sparse,
6174 hash_builder_proof_nodes,
6175 );
6176
6177 for key in &keys_to_delete {
6180 state.remove(key).unwrap();
6181 sparse.remove_leaf(key, &default_provider).unwrap();
6182 }
6183
6184 let mut updated_sparse = sparse.clone();
6188 let sparse_root = updated_sparse.root();
6189 let sparse_updates = updated_sparse.take_updates();
6190
6191 let provider = provider_factory.provider().unwrap();
6192 let trie_cursor = DatabaseTrieCursorFactory::new(provider.tx_ref());
6193 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
6194 run_hash_builder(
6195 state.clone(),
6196 trie_cursor.account_trie_cursor().unwrap(),
6197 keys_to_delete
6198 .iter()
6199 .map(|nibbles| B256::from_slice(&nibbles.pack()))
6200 .collect(),
6201 state.keys().copied(),
6202 );
6203
6204 let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
6206
6207 let provider_rw = provider_factory.provider_rw().unwrap();
6209 provider_rw.write_trie_updates(hash_builder_updates).unwrap();
6210 provider_rw.commit().unwrap();
6211
6212 assert_eq!(sparse_root, hash_builder_root);
6214 pretty_assertions::assert_eq!(
6216 BTreeMap::from_iter(sparse_updates.updated_nodes),
6217 BTreeMap::from_iter(hash_builder_account_nodes)
6218 );
6219 assert_eq_parallel_sparse_trie_proof_nodes(
6221 &updated_sparse,
6222 hash_builder_proof_nodes,
6223 );
6224 }
6225 }
6226 }
6227
6228 fn transform_updates(
6229 updates: Vec<BTreeMap<Nibbles, Account>>,
6230 mut rng: impl rand::Rng,
6231 ) -> Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)> {
6232 let mut keys = BTreeSet::new();
6233 updates
6234 .into_iter()
6235 .map(|update| {
6236 keys.extend(update.keys().copied());
6237
6238 let keys_to_delete_len = update.len() / 2;
6239 let keys_to_delete = (0..keys_to_delete_len)
6240 .map(|_| {
6241 let key =
6242 *rand::seq::IteratorRandom::choose(keys.iter(), &mut rng).unwrap();
6243 keys.take(&key).unwrap()
6244 })
6245 .collect();
6246
6247 (update, keys_to_delete)
6248 })
6249 .collect::<Vec<_>>()
6250 }
6251
6252 proptest!(ProptestConfig::with_cases(10), |(
6253 updates in proptest::collection::vec(
6254 proptest::collection::btree_map(
6255 any_with::<Nibbles>(SizeRange::new(KEY_NIBBLES_LEN..=KEY_NIBBLES_LEN)).prop_map(pad_nibbles_right),
6256 arb::<Account>(),
6257 1..50,
6258 ),
6259 1..50,
6260 ).prop_perturb(transform_updates)
6261 )| {
6262 test(updates)
6263 });
6264 }
6265
6266 #[test]
6267 fn sparse_trie_two_leaves_at_lower_roots() {
6268 let provider = DefaultTrieNodeProvider;
6269 let mut trie = ParallelSparseTrie::default().with_updates(true);
6270 let key_50 = Nibbles::unpack(hex!(
6271 "0x5000000000000000000000000000000000000000000000000000000000000000"
6272 ));
6273 let key_51 = Nibbles::unpack(hex!(
6274 "0x5100000000000000000000000000000000000000000000000000000000000000"
6275 ));
6276
6277 let account = Account::default().into_trie_account(EMPTY_ROOT_HASH);
6278 let mut account_rlp = Vec::new();
6279 account.encode(&mut account_rlp);
6280
6281 trie.update_leaf(key_50, account_rlp.clone(), &provider).unwrap();
6283 trie.root();
6284
6285 trie.update_leaf(key_51, account_rlp.clone(), &provider).unwrap();
6287
6288 let expected_root =
6289 hex!("0xdaf0ef9f91a2f179bb74501209effdb5301db1697bcab041eca2234b126e25de");
6290 let root = trie.root();
6291 assert_eq!(root, expected_root);
6292 assert_eq!(SparseTrieUpdates::default(), trie.take_updates());
6293 }
6294
6295 #[test]
6307 fn sparse_trie_reveal_node_1() {
6308 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00]));
6309 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01]));
6310 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x02]));
6311 let value = || Account::default();
6312 let value_encoded = || {
6313 let mut account_rlp = Vec::new();
6314 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
6315 account_rlp
6316 };
6317
6318 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6320 run_hash_builder(
6321 [(key1(), value()), (key3(), value())],
6322 NoopAccountTrieCursor::default(),
6323 Default::default(),
6324 [Nibbles::default()],
6325 );
6326
6327 let provider = DefaultTrieNodeProvider;
6328 let masks = match (
6329 branch_node_hash_masks.get(&Nibbles::default()).copied(),
6330 branch_node_tree_masks.get(&Nibbles::default()).copied(),
6331 ) {
6332 (Some(h), Some(t)) => Some(BranchNodeMasks { hash_mask: h, tree_mask: t }),
6333 (Some(h), None) => {
6334 Some(BranchNodeMasks { hash_mask: h, tree_mask: TrieMask::default() })
6335 }
6336 (None, Some(t)) => {
6337 Some(BranchNodeMasks { hash_mask: TrieMask::default(), tree_mask: t })
6338 }
6339 (None, None) => None,
6340 };
6341 let mut sparse = ParallelSparseTrie::from_root(
6342 TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
6343 masks,
6344 false,
6345 )
6346 .unwrap();
6347
6348 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6350 run_hash_builder(
6351 [(key1(), value()), (key3(), value())],
6352 NoopAccountTrieCursor::default(),
6353 Default::default(),
6354 [key1()],
6355 );
6356 let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
6357 .nodes_sorted()
6358 .into_iter()
6359 .map(|(path, node)| {
6360 let hash_mask = branch_node_hash_masks.get(&path).copied();
6361 let tree_mask = branch_node_tree_masks.get(&path).copied();
6362 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6363 ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
6364 })
6365 .collect();
6366 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6367
6368 assert_eq!(
6370 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6371 Some(&SparseNode::new_branch(0b101.into()))
6372 );
6373
6374 sparse.update_leaf(key2(), value_encoded(), &provider).unwrap();
6376
6377 assert_eq!(
6379 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6380 Some(&SparseNode::new_branch(0b111.into()))
6381 );
6382
6383 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6385 run_hash_builder(
6386 [(key1(), value()), (key3(), value())],
6387 NoopAccountTrieCursor::default(),
6388 Default::default(),
6389 [key3()],
6390 );
6391 let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
6392 .nodes_sorted()
6393 .into_iter()
6394 .map(|(path, node)| {
6395 let hash_mask = branch_node_hash_masks.get(&path).copied();
6396 let tree_mask = branch_node_tree_masks.get(&path).copied();
6397 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6398 ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
6399 })
6400 .collect();
6401 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6402
6403 assert_eq!(
6405 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6406 Some(&SparseNode::new_branch(0b111.into()))
6407 );
6408
6409 let (_, _, hash_builder_proof_nodes, _, _) = run_hash_builder(
6412 [(key1(), value()), (key2(), value()), (key3(), value())],
6413 NoopAccountTrieCursor::default(),
6414 Default::default(),
6415 [key1(), key2(), key3()],
6416 );
6417
6418 assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
6419 }
6420
6421 #[test]
6432 fn sparse_trie_reveal_node_2() {
6433 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x00]));
6434 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x01]));
6435 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x02]));
6436 let value = || Account::default();
6437
6438 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6440 run_hash_builder(
6441 [(key1(), value()), (key2(), value()), (key3(), value())],
6442 NoopAccountTrieCursor::default(),
6443 Default::default(),
6444 [Nibbles::default()],
6445 );
6446
6447 let provider = DefaultTrieNodeProvider;
6448 let masks = match (
6449 branch_node_hash_masks.get(&Nibbles::default()).copied(),
6450 branch_node_tree_masks.get(&Nibbles::default()).copied(),
6451 ) {
6452 (Some(h), Some(t)) => Some(BranchNodeMasks { hash_mask: h, tree_mask: t }),
6453 (Some(h), None) => {
6454 Some(BranchNodeMasks { hash_mask: h, tree_mask: TrieMask::default() })
6455 }
6456 (None, Some(t)) => {
6457 Some(BranchNodeMasks { hash_mask: TrieMask::default(), tree_mask: t })
6458 }
6459 (None, None) => None,
6460 };
6461 let mut sparse = ParallelSparseTrie::from_root(
6462 TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
6463 masks,
6464 false,
6465 )
6466 .unwrap();
6467
6468 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6471 run_hash_builder(
6472 [(key1(), value()), (key2(), value()), (key3(), value())],
6473 NoopAccountTrieCursor::default(),
6474 Default::default(),
6475 [key1(), Nibbles::from_nibbles_unchecked([0x01])],
6476 );
6477 let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
6478 .nodes_sorted()
6479 .into_iter()
6480 .map(|(path, node)| {
6481 let hash_mask = branch_node_hash_masks.get(&path).copied();
6482 let tree_mask = branch_node_tree_masks.get(&path).copied();
6483 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6484 ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
6485 })
6486 .collect();
6487 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6488
6489 assert_eq!(
6491 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6492 Some(&SparseNode::new_branch(0b11.into()))
6493 );
6494
6495 sparse.remove_leaf(&key1(), &provider).unwrap();
6497
6498 assert_eq!(
6500 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6501 Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
6502 );
6503
6504 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6506 run_hash_builder(
6507 [(key1(), value()), (key2(), value()), (key3(), value())],
6508 NoopAccountTrieCursor::default(),
6509 Default::default(),
6510 [key2()],
6511 );
6512 let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
6513 .nodes_sorted()
6514 .into_iter()
6515 .map(|(path, node)| {
6516 let hash_mask = branch_node_hash_masks.get(&path).copied();
6517 let tree_mask = branch_node_tree_masks.get(&path).copied();
6518 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6519 ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
6520 })
6521 .collect();
6522 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6523
6524 assert_eq!(
6526 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6527 Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
6528 );
6529 }
6530
6531 #[test]
6540 fn sparse_trie_reveal_node_3() {
6541 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x01]));
6542 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x02]));
6543 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x00]));
6544 let value = || Account::default();
6545 let value_encoded = || {
6546 let mut account_rlp = Vec::new();
6547 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
6548 account_rlp
6549 };
6550
6551 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6553 run_hash_builder(
6554 [(key1(), value()), (key2(), value())],
6555 NoopAccountTrieCursor::default(),
6556 Default::default(),
6557 [Nibbles::default()],
6558 );
6559
6560 let provider = DefaultTrieNodeProvider;
6561 let masks = match (
6562 branch_node_hash_masks.get(&Nibbles::default()).copied(),
6563 branch_node_tree_masks.get(&Nibbles::default()).copied(),
6564 ) {
6565 (Some(h), Some(t)) => Some(BranchNodeMasks { hash_mask: h, tree_mask: t }),
6566 (Some(h), None) => {
6567 Some(BranchNodeMasks { hash_mask: h, tree_mask: TrieMask::default() })
6568 }
6569 (None, Some(t)) => {
6570 Some(BranchNodeMasks { hash_mask: TrieMask::default(), tree_mask: t })
6571 }
6572 (None, None) => None,
6573 };
6574 let mut sparse = ParallelSparseTrie::from_root(
6575 TrieNode::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
6576 masks,
6577 false,
6578 )
6579 .unwrap();
6580
6581 assert_matches!(
6583 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6584 Some(SparseNode::Extension { key, hash: None, store_in_db_trie: None }) if *key == Nibbles::from_nibbles([0x00])
6585 );
6586
6587 sparse.update_leaf(key3(), value_encoded(), &provider).unwrap();
6589
6590 assert_matches!(
6592 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6593 Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
6594 );
6595
6596 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6598 run_hash_builder(
6599 [(key1(), value()), (key2(), value())],
6600 NoopAccountTrieCursor::default(),
6601 Default::default(),
6602 [key1()],
6603 );
6604 let mut revealed_nodes: Vec<ProofTrieNode> = hash_builder_proof_nodes
6605 .nodes_sorted()
6606 .into_iter()
6607 .map(|(path, node)| {
6608 let hash_mask = branch_node_hash_masks.get(&path).copied();
6609 let tree_mask = branch_node_tree_masks.get(&path).copied();
6610 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6611 ProofTrieNode { path, node: TrieNode::decode(&mut &node[..]).unwrap(), masks }
6612 })
6613 .collect();
6614 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6615
6616 assert_matches!(
6618 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6619 Some(SparseNode::Branch { state_mask, hash: None, store_in_db_trie: None }) if *state_mask == TrieMask::new(0b11)
6620 );
6621 }
6622
6623 #[test]
6624 fn test_update_leaf_cross_level() {
6625 let ctx = ParallelSparseTrieTestContext;
6626 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6627
6628 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x3, 0x4, 0x5], 1);
6650 trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
6651
6652 ctx.assert_upper_subtrie(&trie)
6654 .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x3, 0x4, 0x5]))
6655 .has_value(&leaf1_path, &value1);
6656
6657 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
6659 trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
6660
6661 ctx.assert_upper_subtrie(&trie)
6663 .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
6664 .has_no_value(&leaf1_path)
6665 .has_no_value(&leaf2_path);
6666
6667 let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x4, 0x5], 3);
6669 trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
6670
6671 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6673 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6674 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
6675 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::from_nibbles([0x5]))
6676 .has_value(&leaf2_path, &value2)
6677 .has_value(&leaf3_path, &value3);
6678
6679 let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x3, 0x3, 0x4], 4);
6681 trie.update_leaf(leaf4_path, value4.clone(), DefaultTrieNodeProvider).unwrap();
6682
6683 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x3]))
6685 .has_value(&leaf1_path, &value1)
6686 .has_value(&leaf4_path, &value4);
6687
6688 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6690 .has_value(&leaf2_path, &value2)
6691 .has_value(&leaf3_path, &value3);
6692
6693 ctx.assert_upper_subtrie(&trie)
6695 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1]))
6696 .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
6697 .has_no_value(&leaf1_path)
6698 .has_no_value(&leaf2_path)
6699 .has_no_value(&leaf3_path)
6700 .has_no_value(&leaf4_path);
6701 }
6702
6703 #[test]
6704 fn test_update_leaf_split_at_level_boundary() {
6705 let ctx = ParallelSparseTrieTestContext;
6706 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6707
6708 let (first_leaf_path, first_value) = ctx.create_test_leaf([0x1, 0x2, 0x2, 0x4], 1);
6723
6724 trie.update_leaf(first_leaf_path, first_value.clone(), DefaultTrieNodeProvider).unwrap();
6725
6726 ctx.assert_upper_subtrie(&trie)
6728 .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x2, 0x4]))
6729 .has_value(&first_leaf_path, &first_value);
6730
6731 let (second_leaf_path, second_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
6733
6734 trie.update_leaf(second_leaf_path, second_value.clone(), DefaultTrieNodeProvider).unwrap();
6735
6736 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6738 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x2, 0x3])
6739 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x2]), &Nibbles::from_nibbles([0x4]))
6740 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
6741 .has_value(&first_leaf_path, &first_value)
6742 .has_value(&second_leaf_path, &second_value);
6743
6744 ctx.assert_upper_subtrie(&trie)
6746 .has_no_value(&first_leaf_path)
6747 .has_no_value(&second_leaf_path);
6748 }
6749
6750 #[test]
6751 fn test_update_subtrie_with_multiple_leaves() {
6752 let ctx = ParallelSparseTrieTestContext;
6753 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6754
6755 let leaves = ctx.create_test_leaves(&[
6769 &[0x1, 0x2, 0x3, 0x4],
6770 &[0x1, 0x2, 0x3, 0x5],
6771 &[0x1, 0x2, 0x4, 0x6],
6772 &[0x1, 0x2, 0x4, 0x7],
6773 ]);
6774
6775 ctx.update_leaves(&mut trie, leaves.clone());
6777
6778 ctx.assert_upper_subtrie(&trie)
6780 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6781
6782 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6784 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6785 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6786 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &[0x6, 0x7])
6787 .has_value(&leaves[0].0, &leaves[0].1)
6788 .has_value(&leaves[1].0, &leaves[1].1)
6789 .has_value(&leaves[2].0, &leaves[2].1)
6790 .has_value(&leaves[3].0, &leaves[3].1);
6791
6792 let updated_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]);
6794 let (_, updated_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 100);
6795
6796 trie.update_leaf(updated_path, updated_value.clone(), DefaultTrieNodeProvider).unwrap();
6797
6798 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6801 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6802 .has_value(&updated_path, &updated_value)
6803 .has_value(&leaves[1].0, &leaves[1].1)
6804 .has_value(&leaves[2].0, &leaves[2].1)
6805 .has_value(&leaves[3].0, &leaves[3].1);
6806
6807 let (new_leaf_path, new_leaf_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 200);
6809
6810 trie.update_leaf(new_leaf_path, new_leaf_value.clone(), DefaultTrieNodeProvider).unwrap();
6811
6812 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6814 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6])
6815 .has_value(&new_leaf_path, &new_leaf_value);
6816 }
6817
6818 #[test]
6819 fn test_update_subtrie_extension_node_subtrie() {
6820 let ctx = ParallelSparseTrieTestContext;
6821 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6822
6823 let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x3, 0x5]]);
6832
6833 ctx.update_leaves(&mut trie, leaves.clone());
6835
6836 ctx.assert_upper_subtrie(&trie)
6838 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6839
6840 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6842 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6843 .has_value(&leaves[0].0, &leaves[0].1)
6844 .has_value(&leaves[1].0, &leaves[1].1);
6845 }
6846
6847 #[test]
6848 fn update_subtrie_extension_node_cross_level() {
6849 let ctx = ParallelSparseTrieTestContext;
6850 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6851
6852 let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x4, 0x5]]);
6862
6863 ctx.update_leaves(&mut trie, leaves.clone());
6865
6866 ctx.assert_upper_subtrie(&trie)
6868 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6869
6870 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6872 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6873 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &Nibbles::from_nibbles([0x4]))
6874 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::from_nibbles([0x5]))
6875 .has_value(&leaves[0].0, &leaves[0].1)
6876 .has_value(&leaves[1].0, &leaves[1].1);
6877 }
6878
6879 #[test]
6880 fn test_update_single_nibble_paths() {
6881 let ctx = ParallelSparseTrieTestContext;
6882 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6883
6884 let (leaf1_path, value1) = ctx.create_test_leaf([0x0], 1);
6896 let (leaf2_path, value2) = ctx.create_test_leaf([0x1], 2);
6897 let (leaf3_path, value3) = ctx.create_test_leaf([0x2], 3);
6898 let (leaf4_path, value4) = ctx.create_test_leaf([0x3], 4);
6899
6900 ctx.update_leaves(
6901 &mut trie,
6902 [
6903 (leaf1_path, value1.clone()),
6904 (leaf2_path, value2.clone()),
6905 (leaf3_path, value3.clone()),
6906 (leaf4_path, value4.clone()),
6907 ],
6908 );
6909
6910 ctx.assert_upper_subtrie(&trie)
6912 .has_branch(&Nibbles::default(), &[0x0, 0x1, 0x2, 0x3])
6913 .has_leaf(&Nibbles::from_nibbles([0x0]), &Nibbles::default())
6914 .has_leaf(&Nibbles::from_nibbles([0x1]), &Nibbles::default())
6915 .has_leaf(&Nibbles::from_nibbles([0x2]), &Nibbles::default())
6916 .has_leaf(&Nibbles::from_nibbles([0x3]), &Nibbles::default())
6917 .has_value(&leaf1_path, &value1)
6918 .has_value(&leaf2_path, &value2)
6919 .has_value(&leaf3_path, &value3)
6920 .has_value(&leaf4_path, &value4);
6921 }
6922
6923 #[test]
6924 fn test_update_deep_extension_chain() {
6925 let ctx = ParallelSparseTrieTestContext;
6926 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6927
6928 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0], 1);
6942 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1], 2);
6943
6944 ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
6945
6946 ctx.assert_upper_subtrie(&trie).has_extension(
6948 &Nibbles::default(),
6949 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
6950 );
6951
6952 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x1]))
6954 .has_branch(&Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]), &[0x0, 0x1])
6955 .has_leaf(
6956 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0]),
6957 &Nibbles::default(),
6958 )
6959 .has_leaf(
6960 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
6961 &Nibbles::default(),
6962 )
6963 .has_value(&leaf1_path, &value1)
6964 .has_value(&leaf2_path, &value2);
6965 }
6966
6967 #[test]
6968 fn test_update_branch_with_all_nibbles() {
6969 let ctx = ParallelSparseTrieTestContext;
6970 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
6971
6972 let mut leaves = Vec::new();
6989 for nibble in 0x0..=0xF {
6990 let (path, value) = ctx.create_test_leaf([0xA, 0x0, nibble], nibble as u64 + 1);
6991 leaves.push((path, value));
6992 }
6993
6994 ctx.update_leaves(&mut trie, leaves.iter().cloned());
6996
6997 ctx.assert_upper_subtrie(&trie)
6999 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0x0]));
7000
7001 let mut subtrie_assert =
7003 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0x0])).has_branch(
7004 &Nibbles::from_nibbles([0xA, 0x0]),
7005 &[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
7006 );
7007
7008 for (i, (path, value)) in leaves.iter().enumerate() {
7010 subtrie_assert = subtrie_assert
7011 .has_leaf(&Nibbles::from_nibbles([0xA, 0x0, i as u8]), &Nibbles::default())
7012 .has_value(path, value);
7013 }
7014 }
7015
7016 #[test]
7017 fn test_update_creates_multiple_subtries() {
7018 let ctx = ParallelSparseTrieTestContext;
7019 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7020
7021 let leaves = [
7037 ctx.create_test_leaf([0x0, 0x0, 0x1, 0x2], 1),
7038 ctx.create_test_leaf([0x0, 0x1, 0x3, 0x4], 2),
7039 ctx.create_test_leaf([0x0, 0x2, 0x5, 0x6], 3),
7040 ctx.create_test_leaf([0x0, 0x3, 0x7, 0x8], 4),
7041 ];
7042
7043 ctx.update_leaves(&mut trie, leaves.iter().cloned());
7045
7046 ctx.assert_upper_subtrie(&trie)
7048 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x0]))
7049 .has_branch(&Nibbles::from_nibbles([0x0]), &[0x0, 0x1, 0x2, 0x3]);
7050
7051 for (i, (leaf_path, leaf_value)) in leaves.iter().enumerate() {
7053 let subtrie_path = Nibbles::from_nibbles([0x0, i as u8]);
7054 ctx.assert_subtrie(&trie, subtrie_path)
7055 .has_leaf(
7056 &subtrie_path,
7057 &Nibbles::from_nibbles(match i {
7058 0 => vec![0x1, 0x2],
7059 1 => vec![0x3, 0x4],
7060 2 => vec![0x5, 0x6],
7061 3 => vec![0x7, 0x8],
7062 _ => unreachable!(),
7063 }),
7064 )
7065 .has_value(leaf_path, leaf_value);
7066 }
7067 }
7068
7069 #[test]
7070 fn test_update_extension_to_branch_transformation() {
7071 let ctx = ParallelSparseTrieTestContext;
7072 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7073
7074 let (leaf1_path, value1) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x1], 1);
7090 let (leaf2_path, value2) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x2], 2);
7091 let (leaf3_path, value3) = ctx.create_test_leaf([0xF, 0x0, 0x0, 0x3], 3);
7092
7093 ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
7094
7095 ctx.assert_upper_subtrie(&trie)
7097 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF, 0xF, 0x0]));
7098
7099 ctx.update_leaves(&mut trie, [(leaf3_path, value3.clone())]);
7101
7102 ctx.assert_upper_subtrie(&trie)
7104 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF]))
7105 .has_branch(&Nibbles::from_nibbles([0xF]), &[0x0, 0xF]);
7106
7107 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
7109 .has_branch(&Nibbles::from_nibbles([0xF, 0xF, 0x0]), &[0x1, 0x2])
7110 .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x1]), &Nibbles::default())
7111 .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x2]), &Nibbles::default())
7112 .has_value(&leaf1_path, &value1)
7113 .has_value(&leaf2_path, &value2);
7114
7115 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0x0]))
7116 .has_leaf(&Nibbles::from_nibbles([0xF, 0x0]), &Nibbles::from_nibbles([0x0, 0x3]))
7117 .has_value(&leaf3_path, &value3);
7118 }
7119
7120 #[test]
7121 fn test_update_upper_extension_reveal_lower_hash_node() {
7122 let ctx = ParallelSparseTrieTestContext;
7123
7124 let mut provider = MockTrieNodeProvider::new();
7147
7148 let child_hashes = [
7150 RlpNode::word_rlp(&B256::repeat_byte(0x11)),
7151 RlpNode::word_rlp(&B256::repeat_byte(0x22)),
7152 ];
7153 let revealed_branch = create_branch_node_with_children(&[0x1, 0x2], child_hashes);
7154 let mut encoded = Vec::new();
7155 revealed_branch.encode(&mut encoded);
7156 provider.add_revealed_node(
7157 Nibbles::from_nibbles([0xA, 0xB]),
7158 RevealedNode { node: encoded.into(), tree_mask: None, hash_mask: None },
7159 );
7160
7161 let mut trie = new_test_trie(
7162 [
7163 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0xA, 0xB]))),
7164 (Nibbles::from_nibbles([0xA, 0xB]), SparseNode::Hash(B256::repeat_byte(0x42))),
7165 ]
7166 .into_iter(),
7167 );
7168
7169 let (leaf_path, value) = ctx.create_test_leaf([0xA, 0x0], 1);
7171 trie.update_leaf(leaf_path, value, provider).unwrap();
7172
7173 ctx.assert_upper_subtrie(&trie)
7175 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA]))
7176 .has_branch(&Nibbles::from_nibbles([0xA]), &[0x0, 0xB]);
7177
7178 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0xB]))
7180 .has_branch(&Nibbles::from_nibbles([0xA, 0xB]), &[0x1, 0x2])
7181 .has_hash(&Nibbles::from_nibbles([0xA, 0xB, 0x1]), &B256::repeat_byte(0x11))
7182 .has_hash(&Nibbles::from_nibbles([0xA, 0xB, 0x2]), &B256::repeat_byte(0x22));
7183 }
7184
7185 #[test]
7186 fn test_update_long_shared_prefix_at_boundary() {
7187 let ctx = ParallelSparseTrieTestContext;
7188 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7189
7190 let (leaf1_path, value1) = ctx.create_test_leaf([0xA, 0xB, 0xC, 0xD, 0xE, 0xF], 1);
7204 let (leaf2_path, value2) = ctx.create_test_leaf([0xA, 0xB, 0xD, 0xE, 0xF, 0x0], 2);
7205
7206 trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
7207 trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
7208
7209 ctx.assert_upper_subtrie(&trie)
7211 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0xB]));
7212
7213 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0xB]))
7215 .has_branch(&Nibbles::from_nibbles([0xA, 0xB]), &[0xC, 0xD])
7216 .has_leaf(
7217 &Nibbles::from_nibbles([0xA, 0xB, 0xC]),
7218 &Nibbles::from_nibbles([0xD, 0xE, 0xF]),
7219 )
7220 .has_leaf(
7221 &Nibbles::from_nibbles([0xA, 0xB, 0xD]),
7222 &Nibbles::from_nibbles([0xE, 0xF, 0x0]),
7223 )
7224 .has_value(&leaf1_path, &value1)
7225 .has_value(&leaf2_path, &value2);
7226 }
7227
7228 #[test]
7229 fn test_update_branch_to_extension_collapse() {
7230 let ctx = ParallelSparseTrieTestContext;
7231 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7232
7233 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
7259 let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
7260 let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
7261
7262 trie.update_leaf(leaf1_path, value1, DefaultTrieNodeProvider).unwrap();
7263 trie.update_leaf(leaf2_path, value2, DefaultTrieNodeProvider).unwrap();
7264 trie.update_leaf(leaf3_path, value3, DefaultTrieNodeProvider).unwrap();
7265
7266 ctx.assert_upper_subtrie(&trie).has_branch(&Nibbles::default(), &[0x1, 0x2]);
7268
7269 let (new_leaf1_path, new_value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 10);
7272 let (new_leaf2_path, new_value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 11);
7273 let (new_leaf3_path, new_value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 12);
7274
7275 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7277 trie.update_leaf(new_leaf1_path, new_value1.clone(), DefaultTrieNodeProvider).unwrap();
7278 trie.update_leaf(new_leaf2_path, new_value2.clone(), DefaultTrieNodeProvider).unwrap();
7279 trie.update_leaf(new_leaf3_path, new_value3.clone(), DefaultTrieNodeProvider).unwrap();
7280
7281 ctx.assert_upper_subtrie(&trie)
7283 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
7284
7285 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
7287
7288 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
7290 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6]) .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &Nibbles::default())
7292 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &Nibbles::default())
7293 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x6]), &Nibbles::default())
7294 .has_value(&new_leaf1_path, &new_value1)
7295 .has_value(&new_leaf2_path, &new_value2)
7296 .has_value(&new_leaf3_path, &new_value3);
7297 }
7298
7299 #[test]
7300 fn test_update_shared_prefix_patterns() {
7301 let ctx = ParallelSparseTrieTestContext;
7302 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7303
7304 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
7320 let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
7321 let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
7322
7323 trie.update_leaf(leaf1_path, value1, DefaultTrieNodeProvider).unwrap();
7324 trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
7325 trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
7326
7327 ctx.assert_upper_subtrie(&trie)
7329 .has_branch(&Nibbles::default(), &[0x1, 0x2])
7330 .has_leaf(&Nibbles::from_nibbles([0x1]), &Nibbles::from_nibbles([0x2, 0x3, 0x4]))
7331 .has_extension(&Nibbles::from_nibbles([0x2]), &Nibbles::from_nibbles([0x3]));
7332
7333 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x2, 0x3]))
7335 .has_branch(&Nibbles::from_nibbles([0x2, 0x3]), &[0x4, 0x5])
7336 .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x4]), &Nibbles::from_nibbles([0x5]))
7337 .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x5]), &Nibbles::from_nibbles([0x6]))
7338 .has_value(&leaf2_path, &value2)
7339 .has_value(&leaf3_path, &value3);
7340 }
7341
7342 #[test]
7343 fn test_progressive_branch_creation() {
7344 let ctx = ParallelSparseTrieTestContext;
7345 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7346
7347 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x5], 1);
7383 trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
7384
7385 ctx.assert_upper_subtrie(&trie)
7387 .has_leaf(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]))
7388 .has_value(&leaf1_path, &value1);
7389
7390 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x6], 2);
7392 trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
7393
7394 ctx.assert_upper_subtrie(&trie)
7396 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
7397
7398 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3, 0x4]);
7400
7401 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
7402 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
7403 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]), &Nibbles::default())
7404 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x6]), &Nibbles::default())
7405 .has_value(&leaf1_path, &value1)
7406 .has_value(&leaf2_path, &value2);
7407
7408 let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 3);
7410 trie.update_leaf(leaf3_path, value3.clone(), DefaultTrieNodeProvider).unwrap();
7411
7412 ctx.assert_upper_subtrie(&trie)
7414 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
7415
7416 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
7418
7419 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
7420 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
7421 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
7422 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &Nibbles::default())
7423 .has_value(&leaf1_path, &value1)
7424 .has_value(&leaf2_path, &value2)
7425 .has_value(&leaf3_path, &value3);
7426
7427 let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x2, 0x4], 4);
7429 trie.update_leaf(leaf4_path, value4.clone(), DefaultTrieNodeProvider).unwrap();
7430
7431 ctx.assert_upper_subtrie(&trie)
7433 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
7434
7435 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2]);
7437
7438 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
7440 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
7441 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
7442 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
7443 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &Nibbles::default())
7444 .has_value(&leaf1_path, &value1)
7445 .has_value(&leaf2_path, &value2)
7446 .has_value(&leaf3_path, &value3)
7447 .has_value(&leaf4_path, &value4);
7448 }
7449
7450 #[test]
7451 fn test_update_max_depth_paths() {
7452 let ctx = ParallelSparseTrieTestContext;
7453 let mut trie = ParallelSparseTrie::from_root(TrieNode::EmptyRoot, None, true).unwrap();
7454
7455 let mut path1_nibbles = vec![0xF; 63];
7467 path1_nibbles.push(0x0);
7468 let mut path2_nibbles = vec![0xF; 63];
7469 path2_nibbles.push(0x1);
7470
7471 let (leaf1_path, value1) = ctx.create_test_leaf(&path1_nibbles, 1);
7472 let (leaf2_path, value2) = ctx.create_test_leaf(&path2_nibbles, 2);
7473
7474 trie.update_leaf(leaf1_path, value1.clone(), DefaultTrieNodeProvider).unwrap();
7475 trie.update_leaf(leaf2_path, value2.clone(), DefaultTrieNodeProvider).unwrap();
7476
7477 let extension_key = vec![0xF; 63];
7479 ctx.assert_upper_subtrie(&trie)
7480 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles(&extension_key));
7481
7482 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
7484 .has_branch(&Nibbles::from_nibbles(&path1_nibbles[..63]), &[0x0, 0x1])
7485 .has_value(&leaf1_path, &value1)
7486 .has_value(&leaf2_path, &value2);
7487 }
7488
7489 #[test]
7490 fn test_hoodie_block_1_data() {
7491 let root_branch_stack = vec![
7493 hex!("a0550b6aba4dd4582a2434d2cbdad8d3007d09f622d7a6e6eaa7a49385823c2fa2"),
7494 hex!("a04788a4975a9e1efd29b834fd80fdfe8a57cc1b1c5ace6d30ce5a36a15e0092b3"),
7495 hex!("a093aeccf87da304e6f7d09edc5d7bd3a552808866d2149dd0940507a8f9bfa910"),
7496 hex!("a08b5b423ba68d0dec2eca1f408076f9170678505eb4a5db2abbbd83bb37666949"),
7497 hex!("a08592f62216af4218098a78acad7cf472a727fb55e6c27d3cfdf2774d4518eb83"),
7498 hex!("a0ef02aeee845cb64c11f85edc1a3094227c26445952554b8a9248915d80c746c3"),
7499 hex!("a0df2529ee3a1ce4df5a758cf17e6a86d0fb5ea22ab7071cf60af6412e9b0a428a"),
7500 hex!("a0acaa1092db69cd5a63676685827b3484c4b80dc1d3361f6073bbb9240101e144"),
7501 hex!("a09c3f2bb2a729d71f246a833353ade65667716bb330e0127a3299a42d11200f93"),
7502 hex!("a0ce978470f4c0b1f8069570563a14d2b79d709add2db4bf22dd9b6aed3271c566"),
7503 hex!("a095f783cd1d464a60e3c8adcadc28c6eb9fec7306664df39553be41dccc909606"),
7504 hex!("a0a9083f5fb914b255e1feb5d951a4dfddacf3c8003ef1d1ec6a13bb6ba5b2ac62"),
7505 hex!("a0fec113d537d8577cd361e0cabf5e95ef58f1cc34318292fdecce9fae57c3e094"),
7506 hex!("a08b7465f5fe8b3e3c0d087cb7521310d4065ef2a0ee43bf73f68dee8a5742b3dd"),
7507 hex!("a0c589aa1ae3d5fd87d8640957f7d5184a4ac06f393b453a8e8ed7e8fba0d385c8"),
7508 hex!("a0b516d6f3352f87beab4ed6e7322f191fc7a147686500ef4de7dd290ad784ef51"),
7509 ];
7510
7511 let root_branch_rlp_stack: Vec<RlpNode> = root_branch_stack
7512 .iter()
7513 .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
7514 .collect();
7515
7516 let root_branch_node = BranchNode::new(
7517 root_branch_rlp_stack,
7518 TrieMask::new(0b1111111111111111), );
7520
7521 let root_branch_masks = Some(BranchNodeMasks {
7522 hash_mask: TrieMask::new(0b1111111111111111),
7523 tree_mask: TrieMask::new(0b1111111111111111),
7524 });
7525
7526 let mut trie = ParallelSparseTrie::from_root(
7527 TrieNode::Branch(root_branch_node),
7528 root_branch_masks,
7529 true,
7530 )
7531 .unwrap();
7532
7533 let branch_0x3_stack = vec![
7535 hex!("a09da7d9755fe0c558b3c3de9fdcdf9f28ae641f38c9787b05b73ab22ae53af3e2"),
7536 hex!("a0d9990bf0b810d1145ecb2b011fd68c63cc85564e6724166fd4a9520180706e5f"),
7537 hex!("a0f60eb4b12132a40df05d9bbdb88bbde0185a3f097f3c76bf4200c23eda26cf86"),
7538 hex!("a0ca976997ddaf06f18992f6207e4f6a05979d07acead96568058789017cc6d06b"),
7539 hex!("a04d78166b48044fdc28ed22d2fd39c8df6f8aaa04cb71d3a17286856f6893ff83"),
7540 hex!("a021d4f90c34d3f1706e78463b6482bca77a3aa1cd059a3f326c42a1cfd30b9b60"),
7541 hex!("a0fc3b71c33e2e6b77c5e494c1db7fdbb447473f003daf378c7a63ba9bf3f0049d"),
7542 hex!("a0e33ed2be194a3d93d343e85642447c93a9d0cfc47a016c2c23d14c083be32a7c"),
7543 hex!("a07b8e7a21c1178d28074f157b50fca85ee25c12568ff8e9706dcbcdacb77bf854"),
7544 hex!("a0973274526811393ea0bf4811ca9077531db00d06b86237a2ecd683f55ba4bcb0"),
7545 hex!("a03a93d726d7487874e51b52d8d534c63aa2a689df18e3b307c0d6cb0a388b00f3"),
7546 hex!("a06aa67101d011d1c22fe739ef83b04b5214a3e2f8e1a2625d8bfdb116b447e86f"),
7547 hex!("a02dd545b33c62d33a183e127a08a4767fba891d9f3b94fc20a2ca02600d6d1fff"),
7548 hex!("a0fe6db87d00f06d53bff8169fa497571ff5af1addfb715b649b4d79dd3e394b04"),
7549 hex!("a0d9240a9d2d5851d05a97ff3305334dfdb0101e1e321fc279d2bb3cad6afa8fc8"),
7550 hex!("a01b69c6ab5173de8a8ec53a6ebba965713a4cc7feb86cb3e230def37c230ca2b2"),
7551 ];
7552
7553 let branch_0x3_rlp_stack: Vec<RlpNode> = branch_0x3_stack
7554 .iter()
7555 .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
7556 .collect();
7557
7558 let branch_0x3_node = BranchNode::new(
7559 branch_0x3_rlp_stack,
7560 TrieMask::new(0b1111111111111111), );
7562
7563 let branch_0x3_masks = Some(BranchNodeMasks {
7564 hash_mask: TrieMask::new(0b0100010000010101),
7565 tree_mask: TrieMask::new(0b0100000000000000),
7566 });
7567
7568 let leaf_path = Nibbles::from_nibbles([0x3, 0x7]);
7570 let leaf_key = Nibbles::unpack(
7571 &hex!("d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42")[..],
7572 );
7573 let leaf_value = hex!("f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0f57acd40259872606d76197ef052f3d35588dadf919ee1f0e3cb9b62d3f4b02c").to_vec();
7574
7575 let leaf_node = LeafNode::new(leaf_key, leaf_value);
7576 let leaf_masks = None;
7577
7578 trie.reveal_nodes(&mut [
7579 ProofTrieNode {
7580 path: Nibbles::from_nibbles([0x3]),
7581 node: TrieNode::Branch(branch_0x3_node),
7582 masks: branch_0x3_masks,
7583 },
7584 ProofTrieNode { path: leaf_path, node: TrieNode::Leaf(leaf_node), masks: leaf_masks },
7585 ])
7586 .unwrap();
7587
7588 let mut leaf_full_path = leaf_path;
7590 leaf_full_path.extend(&leaf_key);
7591
7592 let leaf_new_value = vec![
7593 248, 68, 1, 128, 160, 224, 163, 152, 169, 122, 160, 155, 102, 53, 41, 0, 47, 28, 205,
7594 190, 199, 5, 215, 108, 202, 22, 138, 70, 196, 178, 193, 208, 18, 96, 95, 63, 238, 160,
7595 245, 122, 205, 64, 37, 152, 114, 96, 109, 118, 25, 126, 240, 82, 243, 211, 85, 136,
7596 218, 223, 145, 158, 225, 240, 227, 203, 155, 98, 211, 244, 176, 44,
7597 ];
7598
7599 trie.update_leaf(leaf_full_path, leaf_new_value.clone(), DefaultTrieNodeProvider).unwrap();
7600
7601 assert_eq!(
7603 Some(&leaf_new_value),
7604 trie.lower_subtrie_for_path(&leaf_path).unwrap().inner.values.get(&leaf_full_path)
7605 );
7606 assert!(trie.upper_subtrie.inner.values.is_empty());
7607
7608 let expected_root =
7610 b256!("0x29b07de8376e9ce7b3a69e9b102199869514d3f42590b5abc6f7d48ec9b8665c");
7611 assert_eq!(trie.root(), expected_root);
7612 }
7613
7614 #[test]
7615 fn find_leaf_existing_leaf() {
7616 let provider = DefaultTrieNodeProvider;
7618 let mut sparse = ParallelSparseTrie::default();
7619 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
7620 let value = b"test_value".to_vec();
7621
7622 sparse.update_leaf(path, value.clone(), &provider).unwrap();
7623
7624 let result = sparse.find_leaf(&path, None);
7626 assert_matches!(result, Ok(LeafLookup::Exists));
7627
7628 let result = sparse.find_leaf(&path, Some(&value));
7630 assert_matches!(result, Ok(LeafLookup::Exists));
7631 }
7632
7633 #[test]
7634 fn find_leaf_value_mismatch() {
7635 let provider = DefaultTrieNodeProvider;
7637 let mut sparse = ParallelSparseTrie::default();
7638 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
7639 let value = b"test_value".to_vec();
7640 let wrong_value = b"wrong_value".to_vec();
7641
7642 sparse.update_leaf(path, value, &provider).unwrap();
7643
7644 let result = sparse.find_leaf(&path, Some(&wrong_value));
7646 assert_matches!(
7647 result,
7648 Err(LeafLookupError::ValueMismatch { path: p, expected: Some(e), actual: _a }) if p == path && e == wrong_value
7649 );
7650 }
7651
7652 #[test]
7653 fn find_leaf_not_found_empty_trie() {
7654 let sparse = ParallelSparseTrie::default();
7656 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
7657
7658 let result = sparse.find_leaf(&path, None);
7660 assert_matches!(result, Ok(LeafLookup::NonExistent));
7661 }
7662
7663 #[test]
7664 fn find_leaf_empty_trie() {
7665 let sparse = ParallelSparseTrie::default();
7666 let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7667
7668 let result = sparse.find_leaf(&path, None);
7669 assert_matches!(result, Ok(LeafLookup::NonExistent));
7670 }
7671
7672 #[test]
7673 fn find_leaf_exists_no_value_check() {
7674 let provider = DefaultTrieNodeProvider;
7675 let mut sparse = ParallelSparseTrie::default();
7676 let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7677 sparse.update_leaf(path, encode_account_value(0), &provider).unwrap();
7678
7679 let result = sparse.find_leaf(&path, None);
7680 assert_matches!(result, Ok(LeafLookup::Exists));
7681 }
7682
7683 #[test]
7684 fn find_leaf_exists_with_value_check_ok() {
7685 let provider = DefaultTrieNodeProvider;
7686 let mut sparse = ParallelSparseTrie::default();
7687 let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7688 let value = encode_account_value(0);
7689 sparse.update_leaf(path, value.clone(), &provider).unwrap();
7690
7691 let result = sparse.find_leaf(&path, Some(&value));
7692 assert_matches!(result, Ok(LeafLookup::Exists));
7693 }
7694
7695 #[test]
7696 fn find_leaf_exclusion_branch_divergence() {
7697 let provider = DefaultTrieNodeProvider;
7698 let mut sparse = ParallelSparseTrie::default();
7699 let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]); let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]); sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
7704 sparse.update_leaf(path2, encode_account_value(1), &provider).unwrap();
7705
7706 let result = sparse.find_leaf(&search_path, None);
7707 assert_matches!(result, Ok(LeafLookup::NonExistent))
7708 }
7709
7710 #[test]
7711 fn find_leaf_exclusion_extension_divergence() {
7712 let provider = DefaultTrieNodeProvider;
7713 let mut sparse = ParallelSparseTrie::default();
7714 let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
7716 let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x7, 0x8]);
7718
7719 sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
7720
7721 let result = sparse.find_leaf(&search_path, None);
7722 assert_matches!(result, Ok(LeafLookup::NonExistent))
7723 }
7724
7725 #[test]
7726 fn find_leaf_exclusion_leaf_divergence() {
7727 let provider = DefaultTrieNodeProvider;
7728 let mut sparse = ParallelSparseTrie::default();
7729 let existing_leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7730 let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
7731
7732 sparse.update_leaf(existing_leaf_path, encode_account_value(0), &provider).unwrap();
7733
7734 let result = sparse.find_leaf(&search_path, None);
7735 assert_matches!(result, Ok(LeafLookup::NonExistent))
7736 }
7737
7738 #[test]
7739 fn find_leaf_exclusion_path_ends_at_branch() {
7740 let provider = DefaultTrieNodeProvider;
7741 let mut sparse = ParallelSparseTrie::default();
7742 let path1 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]); let path2 = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x5, 0x6]);
7744 let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2]); sparse.update_leaf(path1, encode_account_value(0), &provider).unwrap();
7747 sparse.update_leaf(path2, encode_account_value(1), &provider).unwrap();
7748
7749 let result = sparse.find_leaf(&search_path, None);
7750 assert_matches!(result, Ok(LeafLookup::NonExistent));
7751 }
7752
7753 #[test]
7754 fn find_leaf_error_blinded_node_at_leaf_path() {
7755 let blinded_hash = B256::repeat_byte(0xBB);
7757 let leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7758
7759 let sparse = new_test_trie(
7760 [
7761 (
7762 Nibbles::default(),
7764 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x1, 0x2])),
7765 ),
7766 (
7767 Nibbles::from_nibbles_unchecked([0x1, 0x2]),
7769 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x3])),
7770 ),
7771 (
7772 Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3]),
7774 SparseNode::new_branch(TrieMask::new(0b10000)),
7775 ),
7776 (
7777 leaf_path,
7779 SparseNode::Hash(blinded_hash),
7780 ),
7781 ]
7782 .into_iter(),
7783 );
7784
7785 let result = sparse.find_leaf(&leaf_path, None);
7786
7787 assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
7789 if path == leaf_path && hash == blinded_hash
7790 );
7791 }
7792
7793 #[test]
7794 fn find_leaf_error_blinded_node() {
7795 let blinded_hash = B256::repeat_byte(0xAA);
7796 let path_to_blind = Nibbles::from_nibbles_unchecked([0x1]);
7797 let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7798
7799 let sparse = new_test_trie(
7800 [
7801 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b100010))),
7804 (path_to_blind, SparseNode::Hash(blinded_hash)),
7805 (
7806 Nibbles::from_nibbles_unchecked([0x5]),
7807 SparseNode::new_leaf(Nibbles::from_nibbles_unchecked([0x6, 0x7, 0x8])),
7808 ),
7809 ]
7810 .into_iter(),
7811 );
7812
7813 let result = sparse.find_leaf(&search_path, None);
7814
7815 assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
7817 if path == path_to_blind && hash == blinded_hash
7818 );
7819 }
7820
7821 #[test]
7822 fn test_mainnet_block_24185431_storage_0x6ba784ee() {
7823 reth_tracing::init_test_tracing();
7824
7825 let mut branch_0x3_hashes = vec![
7827 B256::from(hex!("fc11ba8de4b220b8f19a09f0676c69b8e18bae1350788392640069e59b41733d")),
7828 B256::from(hex!("8afe085cc6685680bd8ba4bac6e65937a4babf737dc5e7413d21cdda958e8f74")),
7829 B256::from(hex!("c7b6f7c0fc601a27aece6ec178fd9be17cdee77c4884ecfbe1ee459731eb57da")),
7830 B256::from(hex!("71c1aec60db78a2deb4e10399b979a2ed5be42b4ee0c0a17c614f9ddc9f9072e")),
7831 B256::from(hex!("e9261302e7c0b77930eaf1851b585210906cd01e015ab6be0f7f3c0cc947c32a")),
7832 B256::from(hex!("38ce8f369c56bd77fabdf679b27265b1f8d0a54b09ef612c8ee8ddfc6b3fab95")),
7833 B256::from(hex!("7b507a8936a28c5776b647d1c4bda0bbbb3d0d227f16c5f5ebba58d02e31918d")),
7834 B256::from(hex!("0f456b9457a824a81e0eb555aa861461acb38674dcf36959b3b26deb24ed0af9")),
7835 B256::from(hex!("2145420289652722ad199ba932622e3003c779d694fa5a2acfb2f77b0782b38a")),
7836 B256::from(hex!("2c1a04dce1a9e2f1cfbf8806edce50a356dfa58e7e7c542c848541502613b796")),
7837 B256::from(hex!("dad7ca55186ac8f40d4450dc874166df8267b44abc07e684d9507260f5712df3")),
7838 B256::from(hex!("3a8c2a1d7d2423e92965ec29014634e7f0307ded60b1a63d28c86c3222b24236")),
7839 B256::from(hex!("4e9929e6728b3a7bf0db6a0750ab376045566b556c9c605e606ecb8ec25200d7")),
7840 B256::from(hex!("1797c36f98922f52292c161590057a1b5582d5503e3370bcfbf6fd939f3ec98b")),
7841 B256::from(hex!("9e514589a9c9210b783c19fa3f0b384bbfaefe98f10ea189a2bfc58c6bf000a1")),
7842 B256::from(hex!("85bdaabbcfa583cbd049650e41d3d19356bd833b3ed585cf225a3548557c7fa3")),
7843 ];
7844 let branch_0x3_node = create_branch_node_with_children(
7845 &[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf],
7846 branch_0x3_hashes.iter().map(RlpNode::word_rlp),
7847 );
7848
7849 let branch_0x31_hashes = vec![B256::from(hex!(
7851 "3ca994ba59ce70b83fee1f01731c8dac4fdd0f70ade79bf9b0695c4c53531aab"
7852 ))];
7853 let branch_0x31_node = create_branch_node_with_children(
7854 &[0xc],
7855 branch_0x31_hashes.into_iter().map(|h| RlpNode::word_rlp(&h)),
7856 );
7857
7858 let leaf_path = hex!("31b0b645a6c4a0a1bb3d2f0c1d31c39f4aba2e3b015928a8eef7161e28388b81");
7860 let leaf_nibbles = Nibbles::unpack(leaf_path.as_slice());
7861 let leaf_value = hex!("0009ae8ce8245bff").to_vec();
7862
7863 let branch_0x31c_hashes = vec![
7865 B256::from(hex!("1a68fdb36b77e9332b49a977faf800c22d0199e6cecf44032bb083c78943e540")),
7866 B256::from(hex!("cd4622c6df6fd7172c7fed1b284ef241e0f501b4c77b675ef10c612bd0948a7a")),
7867 B256::from(hex!("abf3603d2f991787e21f1709ee4c7375d85dfc506995c0435839fccf3fe2add4")),
7868 ];
7869 let branch_0x31c_node = create_branch_node_with_children(
7870 &[0x3, 0x7, 0xc],
7871 branch_0x31c_hashes.into_iter().map(|h| RlpNode::word_rlp(&h)),
7872 );
7873 let mut branch_0x31c_node_encoded = Vec::new();
7874 branch_0x31c_node.encode(&mut branch_0x31c_node_encoded);
7875
7876 let mut provider = MockTrieNodeProvider::new();
7878 provider.add_revealed_node(
7879 Nibbles::from_nibbles([0x3, 0x1, 0xc]),
7880 RevealedNode {
7881 node: branch_0x31c_node_encoded.into(),
7882 tree_mask: Some(0.into()),
7883 hash_mask: Some(4096.into()),
7884 },
7885 );
7886
7887 let mut proof_nodes = vec![
7889 ProofTrieNode {
7890 path: Nibbles::from_nibbles([0x3]),
7891 node: branch_0x3_node,
7892 masks: Some(BranchNodeMasks {
7893 tree_mask: TrieMask::new(26099),
7894 hash_mask: TrieMask::new(65535),
7895 }),
7896 },
7897 ProofTrieNode {
7898 path: Nibbles::from_nibbles([0x3, 0x1]),
7899 node: branch_0x31_node,
7900 masks: Some(BranchNodeMasks {
7901 tree_mask: TrieMask::new(4096),
7902 hash_mask: TrieMask::new(4096),
7903 }),
7904 },
7905 ];
7906
7907 let mut trie = ParallelSparseTrie::default()
7909 .with_root(
7910 TrieNode::Extension(ExtensionNode {
7911 key: Nibbles::from_nibbles([0x3]),
7912 child: RlpNode::word_rlp(&B256::ZERO),
7913 }),
7914 None,
7915 true,
7916 )
7917 .expect("root revealed");
7918
7919 trie.reveal_nodes(&mut proof_nodes).unwrap();
7920
7921 trie.update_leaf(leaf_nibbles, leaf_value, &provider).unwrap();
7923
7924 trie.remove_leaf(&leaf_nibbles, &provider).unwrap();
7926
7927 let _ = trie.root();
7929
7930 let updates = trie.updates_ref();
7932
7933 let branch_0x3_update = updates
7935 .updated_nodes
7936 .get(&Nibbles::from_nibbles([0x3]))
7937 .expect("Branch at 0x3 should be in updates");
7938
7939 branch_0x3_hashes.remove(1);
7941
7942 let expected_branch = BranchNodeCompact::new(
7944 0b1111111111111111,
7945 0b0110010111110011,
7946 0b1111111111111101,
7947 branch_0x3_hashes,
7948 None,
7949 );
7950
7951 assert_eq!(branch_0x3_update, &expected_branch);
7952 }
7953
7954 #[test]
7955 fn test_get_leaf_value_lower_subtrie() {
7956 let root_branch =
7962 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
7963 let branch_at_1 =
7964 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xBB))]);
7965 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
7966 trie.reveal_nodes(&mut [ProofTrieNode {
7967 path: Nibbles::from_nibbles([0x1]),
7968 node: branch_at_1,
7969 masks: None,
7970 }])
7971 .unwrap();
7972
7973 let leaf_path = Nibbles::from_nibbles([0x1, 0x2]);
7975 let leaf_key = Nibbles::from_nibbles([0x3, 0x4]);
7976 let leaf_node = create_leaf_node(leaf_key.to_vec(), 42);
7977
7978 trie.reveal_nodes(&mut [ProofTrieNode { path: leaf_path, node: leaf_node, masks: None }])
7980 .unwrap();
7981
7982 let full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]);
7984
7985 let idx = path_subtrie_index_unchecked(&leaf_path);
7987 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
7988 assert!(
7989 lower_subtrie.inner.values.contains_key(&full_path),
7990 "value should be in lower subtrie"
7991 );
7992 assert!(
7993 !trie.upper_subtrie.inner.values.contains_key(&full_path),
7994 "value should NOT be in upper subtrie"
7995 );
7996
7997 assert!(
7999 trie.get_leaf_value(&full_path).is_some(),
8000 "get_leaf_value should find the value in lower subtrie"
8001 );
8002 }
8003
8004 #[test]
8011 fn test_get_leaf_value_upper_subtrie_via_update_leaf() {
8012 let provider = MockTrieNodeProvider::new();
8013
8014 let mut trie = ParallelSparseTrie::default()
8016 .with_root(TrieNode::EmptyRoot, None, false)
8017 .expect("root revealed");
8018
8019 let full_path = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0xA, 0xB, 0xC]));
8021 let value = encode_account_value(42);
8022
8023 trie.update_leaf(full_path, value.clone(), &provider).unwrap();
8026
8027 assert!(
8029 trie.upper_subtrie.inner.values.contains_key(&full_path),
8030 "value should be in upper subtrie after update_leaf"
8031 );
8032
8033 let retrieved = trie.get_leaf_value(&full_path);
8037 assert_eq!(retrieved, Some(&value));
8038 }
8039
8040 #[test]
8042 fn test_get_leaf_value_upper_and_lower_subtries() {
8043 let provider = MockTrieNodeProvider::new();
8044
8045 let mut trie = ParallelSparseTrie::default()
8047 .with_root(TrieNode::EmptyRoot, None, false)
8048 .expect("root revealed");
8049
8050 let path1 = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0xA]));
8052 let value1 = encode_account_value(1);
8053 trie.update_leaf(path1, value1.clone(), &provider).unwrap();
8054
8055 let path2 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0xB]));
8057 let value2 = encode_account_value(2);
8058 trie.update_leaf(path2, value2.clone(), &provider).unwrap();
8059
8060 assert_eq!(trie.get_leaf_value(&path1), Some(&value1));
8062 assert_eq!(trie.get_leaf_value(&path2), Some(&value2));
8063 }
8064
8065 #[test]
8067 fn test_get_leaf_value_sparse_storage_trie() {
8068 let provider = MockTrieNodeProvider::new();
8069
8070 let mut trie = ParallelSparseTrie::default()
8072 .with_root(TrieNode::EmptyRoot, None, false)
8073 .expect("root revealed");
8074
8075 let slot_path = pad_nibbles_right(Nibbles::from_nibbles([0x2, 0x9]));
8077 let slot_value = alloy_rlp::encode(U256::from(12345));
8078 trie.update_leaf(slot_path, slot_value.clone(), &provider).unwrap();
8079
8080 assert_eq!(trie.get_leaf_value(&slot_path), Some(&slot_value));
8082 }
8083
8084 #[test]
8085 fn test_prune_empty_suffix_key_regression() {
8086 use crate::provider::DefaultTrieNodeProvider;
8091
8092 let provider = DefaultTrieNodeProvider;
8093 let mut parallel = ParallelSparseTrie::default();
8094
8095 let value = {
8097 let account = Account {
8098 nonce: 0x123456789abcdef,
8099 balance: U256::from(0x123456789abcdef0123456789abcdef_u128),
8100 ..Default::default()
8101 };
8102 let mut buf = Vec::new();
8103 account.into_trie_account(EMPTY_ROOT_HASH).encode(&mut buf);
8104 buf
8105 };
8106
8107 for i in 0..16u8 {
8109 parallel
8110 .update_leaf(
8111 Nibbles::from_nibbles([i, 0x1, 0x2, 0x3, 0x4, 0x5]),
8112 value.clone(),
8113 &provider,
8114 )
8115 .unwrap();
8116 }
8117
8118 let root_before = parallel.root();
8120
8121 parallel.prune(0);
8123
8124 let root_after = parallel.root();
8125 assert_eq!(root_before, root_after, "root hash must be preserved");
8126
8127 for i in 0..16u8 {
8130 let path = Nibbles::from_nibbles([i, 0x1, 0x2, 0x3, 0x4, 0x5]);
8131 assert!(
8132 parallel.get_leaf_value(&path).is_none(),
8133 "value at {:?} should be removed after prune",
8134 path
8135 );
8136 }
8137 }
8138
8139 #[test]
8140 fn test_prune_at_various_depths() {
8141 for max_depth in [0, 1] {
8146 let provider = DefaultTrieNodeProvider;
8147 let mut trie = ParallelSparseTrie::default();
8148
8149 let value = large_account_value();
8150
8151 for i in 0..4u8 {
8152 for j in 0..4u8 {
8153 for k in 0..4u8 {
8154 trie.update_leaf(
8155 Nibbles::from_nibbles([i, j, k, 0x1, 0x2, 0x3]),
8156 value.clone(),
8157 &provider,
8158 )
8159 .unwrap();
8160 }
8161 }
8162 }
8163
8164 let root_before = trie.root();
8165 let nodes_before = trie.size_hint();
8166
8167 for _ in 0..2 {
8171 trie.prune(max_depth);
8172 }
8173
8174 let root_after = trie.root();
8175 assert_eq!(root_before, root_after, "root hash should be preserved after prune");
8176
8177 let nodes_after = trie.size_hint();
8178 assert!(
8179 nodes_after < nodes_before,
8180 "node count should decrease after prune at depth {max_depth}"
8181 );
8182
8183 if max_depth == 0 {
8184 assert_eq!(nodes_after, 5, "root + 4 hash stubs after prune(0)");
8186 }
8187 }
8188 }
8189
8190 #[test]
8191 fn test_prune_empty_trie() {
8192 let mut trie = ParallelSparseTrie::default();
8193 trie.prune(2);
8194 let root = trie.root();
8195 assert_eq!(root, EMPTY_ROOT_HASH, "empty trie should have empty root hash");
8196 }
8197
8198 #[test]
8199 fn test_prune_preserves_root_hash() {
8200 let provider = DefaultTrieNodeProvider;
8201 let mut trie = ParallelSparseTrie::default();
8202
8203 let value = large_account_value();
8204
8205 for i in 0..8u8 {
8206 for j in 0..4u8 {
8207 trie.update_leaf(
8208 Nibbles::from_nibbles([i, j, 0x3, 0x4, 0x5, 0x6]),
8209 value.clone(),
8210 &provider,
8211 )
8212 .unwrap();
8213 }
8214 }
8215
8216 let root_before = trie.root();
8217 trie.prune(1);
8218 let root_after = trie.root();
8219 assert_eq!(root_before, root_after, "root hash must be preserved after prune");
8220 }
8221
8222 #[test]
8223 fn test_prune_single_leaf_trie() {
8224 let provider = DefaultTrieNodeProvider;
8225 let mut trie = ParallelSparseTrie::default();
8226
8227 let value = large_account_value();
8228 trie.update_leaf(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), value, &provider).unwrap();
8229
8230 let root_before = trie.root();
8231 let nodes_before = trie.size_hint();
8232
8233 trie.prune(0);
8234
8235 let root_after = trie.root();
8236 assert_eq!(root_before, root_after, "root hash should be preserved");
8237 assert_eq!(trie.size_hint(), nodes_before, "single leaf trie should not change");
8238 }
8239
8240 #[test]
8241 fn test_prune_deep_depth_no_effect() {
8242 let provider = DefaultTrieNodeProvider;
8243 let mut trie = ParallelSparseTrie::default();
8244
8245 let value = large_account_value();
8246
8247 for i in 0..4u8 {
8248 trie.update_leaf(Nibbles::from_nibbles([i, 0x2, 0x3, 0x4]), value.clone(), &provider)
8249 .unwrap();
8250 }
8251
8252 trie.root();
8253 let nodes_before = trie.size_hint();
8254
8255 trie.prune(100);
8256
8257 assert_eq!(nodes_before, trie.size_hint(), "deep prune should have no effect");
8258 }
8259
8260 #[test]
8261 fn test_prune_extension_node_depth_semantics() {
8262 let provider = DefaultTrieNodeProvider;
8263 let mut trie = ParallelSparseTrie::default();
8264
8265 let value = large_account_value();
8266
8267 trie.update_leaf(Nibbles::from_nibbles([0, 1, 2, 3, 0, 5, 6, 7]), value.clone(), &provider)
8268 .unwrap();
8269 trie.update_leaf(Nibbles::from_nibbles([0, 1, 2, 3, 1, 5, 6, 7]), value, &provider)
8270 .unwrap();
8271
8272 let root_before = trie.root();
8273 for _ in 0..2 {
8277 trie.prune(1);
8278 }
8279
8280 assert_eq!(root_before, trie.root(), "root hash should be preserved");
8281 assert_eq!(trie.size_hint(), 4, "root + extension + hash stubs after prune(1)");
8283 }
8284
8285 #[test]
8286 fn test_prune_embedded_node_preserved() {
8287 let provider = DefaultTrieNodeProvider;
8288 let mut trie = ParallelSparseTrie::default();
8289
8290 let small_value = vec![0x80];
8291 trie.update_leaf(Nibbles::from_nibbles([0x0]), small_value.clone(), &provider).unwrap();
8292 trie.update_leaf(Nibbles::from_nibbles([0x1]), small_value, &provider).unwrap();
8293
8294 let root_before = trie.root();
8295 let nodes_before = trie.size_hint();
8296
8297 trie.prune(0);
8298
8299 assert_eq!(root_before, trie.root(), "root hash must be preserved");
8300
8301 if trie.size_hint() == nodes_before {
8302 assert!(trie.get_leaf_value(&Nibbles::from_nibbles([0x0])).is_some());
8303 assert!(trie.get_leaf_value(&Nibbles::from_nibbles([0x1])).is_some());
8304 }
8305 }
8306
8307 #[test]
8308 fn test_prune_mixed_embedded_and_hashed() {
8309 let provider = DefaultTrieNodeProvider;
8310 let mut trie = ParallelSparseTrie::default();
8311
8312 let large_value = large_account_value();
8313 let small_value = vec![0x80];
8314
8315 for i in 0..8u8 {
8316 let value = if i < 4 { large_value.clone() } else { small_value.clone() };
8317 trie.update_leaf(Nibbles::from_nibbles([i, 0x1, 0x2, 0x3]), value, &provider).unwrap();
8318 }
8319
8320 let root_before = trie.root();
8321 trie.prune(0);
8322 assert_eq!(root_before, trie.root(), "root hash must be preserved");
8323 }
8324
8325 #[test]
8326 fn test_prune_many_lower_subtries() {
8327 let provider = DefaultTrieNodeProvider;
8328
8329 let large_value = large_account_value();
8330
8331 let mut keys = Vec::new();
8332 for first in 0..16u8 {
8333 for second in 0..16u8 {
8334 keys.push(Nibbles::from_nibbles([first, second, 0x1, 0x2, 0x3, 0x4]));
8335 }
8336 }
8337
8338 let mut trie = ParallelSparseTrie::default();
8339
8340 for key in &keys {
8341 trie.update_leaf(*key, large_value.clone(), &provider).unwrap();
8342 }
8343
8344 let root_before = trie.root();
8345
8346 let mut total_pruned = 0;
8349 for _ in 0..2 {
8350 total_pruned += trie.prune(1);
8351 }
8352
8353 assert!(total_pruned > 0, "should have pruned some nodes");
8354 assert_eq!(root_before, trie.root(), "root hash should be preserved");
8355
8356 for key in &keys {
8357 assert!(trie.get_leaf_value(key).is_none(), "value should be pruned");
8358 }
8359 }
8360
8361 #[test]
8362 fn test_prune_max_depth_overflow() {
8363 let provider = DefaultTrieNodeProvider;
8365 let mut trie = ParallelSparseTrie::default();
8366
8367 let value = large_account_value();
8368
8369 for i in 0..4u8 {
8370 trie.update_leaf(Nibbles::from_nibbles([i, 0x1, 0x2, 0x3]), value.clone(), &provider)
8371 .unwrap();
8372 }
8373
8374 trie.root();
8375 let nodes_before = trie.size_hint();
8376
8377 trie.prune(300);
8379
8380 assert_eq!(
8381 nodes_before,
8382 trie.size_hint(),
8383 "prune(300) should have no effect on a shallow trie"
8384 );
8385 }
8386
8387 #[test]
8388 fn test_prune_fast_path_case2_update_after() {
8389 let provider = DefaultTrieNodeProvider;
8392 let mut trie = ParallelSparseTrie::default();
8393
8394 let value = large_account_value();
8395
8396 for first in 0..4u8 {
8399 for second in 0..4u8 {
8400 trie.update_leaf(
8401 Nibbles::from_nibbles([first, second, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6]),
8402 value.clone(),
8403 &provider,
8404 )
8405 .unwrap();
8406 }
8407 }
8408
8409 let root_before = trie.root();
8410
8411 trie.prune(0);
8413
8414 let root_after = trie.root();
8415 assert_eq!(root_before, root_after, "root hash should be preserved");
8416
8417 let new_path = Nibbles::from_nibbles([0x5, 0x5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6]);
8420 trie.update_leaf(new_path, value, &provider).unwrap();
8421
8422 let _ = trie.root();
8424 }
8425
8426 #[test]
8429 fn test_update_leaves_successful_update() {
8430 use crate::LeafUpdate;
8431 use alloy_primitives::map::B256Map;
8432 use std::cell::RefCell;
8433
8434 let provider = DefaultTrieNodeProvider;
8435 let mut trie = ParallelSparseTrie::default();
8436
8437 let b256_key = B256::with_last_byte(42);
8439 let key = Nibbles::unpack(b256_key);
8440 let value = encode_account_value(1);
8441 trie.update_leaf(key, value, &provider).unwrap();
8442
8443 let new_value = encode_account_value(2);
8445
8446 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8447 updates.insert(b256_key, LeafUpdate::Changed(new_value));
8448
8449 let proof_targets = RefCell::new(Vec::new());
8450 trie.update_leaves(&mut updates, |path, min_len| {
8451 proof_targets.borrow_mut().push((path, min_len));
8452 })
8453 .unwrap();
8454
8455 assert!(updates.is_empty(), "Update map should be empty after successful update");
8457 assert!(
8458 proof_targets.borrow().is_empty(),
8459 "Callback should not be invoked for revealed paths"
8460 );
8461 }
8462
8463 #[test]
8464 fn test_update_leaves_insert_new_leaf() {
8465 use crate::LeafUpdate;
8466 use alloy_primitives::map::B256Map;
8467 use std::cell::RefCell;
8468
8469 let mut trie = ParallelSparseTrie::default();
8470
8471 let b256_key = B256::with_last_byte(99);
8473 let new_value = encode_account_value(42);
8474
8475 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8476 updates.insert(b256_key, LeafUpdate::Changed(new_value.clone()));
8477
8478 let proof_targets = RefCell::new(Vec::new());
8479 trie.update_leaves(&mut updates, |path, min_len| {
8480 proof_targets.borrow_mut().push((path, min_len));
8481 })
8482 .unwrap();
8483
8484 assert!(updates.is_empty(), "Update map should be empty after successful insert");
8486 assert!(
8487 proof_targets.borrow().is_empty(),
8488 "Callback should not be invoked for new leaf insert"
8489 );
8490
8491 let full_path = Nibbles::unpack(b256_key);
8493 assert_eq!(
8494 trie.get_leaf_value(&full_path),
8495 Some(&new_value),
8496 "New leaf value should be retrievable"
8497 );
8498 }
8499
8500 #[test]
8501 fn test_update_leaves_blinded_node() {
8502 use crate::LeafUpdate;
8503 use alloy_primitives::map::B256Map;
8504 use std::cell::RefCell;
8505
8506 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8509 let leaf = LeafNode::new(
8510 Nibbles::default(), small_value,
8512 );
8513 let branch = TrieNode::Branch(BranchNode::new(
8514 vec![
8515 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8518 TrieMask::new(0b11),
8519 ));
8520
8521 let mut trie = ParallelSparseTrie::from_root(
8522 branch.clone(),
8523 Some(BranchNodeMasks {
8524 hash_mask: TrieMask::new(0b01),
8525 tree_mask: TrieMask::default(),
8526 }),
8527 false,
8528 )
8529 .unwrap();
8530
8531 trie.reveal_node(
8533 Nibbles::default(),
8534 branch,
8535 Some(BranchNodeMasks {
8536 hash_mask: TrieMask::default(),
8537 tree_mask: TrieMask::new(0b01),
8538 }),
8539 )
8540 .unwrap();
8541 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), None).unwrap();
8542
8543 let b256_key = B256::ZERO; let new_value = encode_account_value(42);
8548 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8549 updates.insert(b256_key, LeafUpdate::Changed(new_value));
8550
8551 let proof_targets = RefCell::new(Vec::new());
8552 let prefix_set_len_before = trie.prefix_set.len();
8553 trie.update_leaves(&mut updates, |path, min_len| {
8554 proof_targets.borrow_mut().push((path, min_len));
8555 })
8556 .unwrap();
8557
8558 assert!(!updates.is_empty(), "Update should remain in map when hitting blinded node");
8560
8561 assert_eq!(
8563 trie.prefix_set.len(),
8564 prefix_set_len_before,
8565 "prefix_set should be unchanged after failed update on blinded node"
8566 );
8567
8568 let targets = proof_targets.borrow();
8570 assert!(!targets.is_empty(), "Callback should be invoked for blinded path");
8571
8572 assert_eq!(targets[0].1, 1, "min_len should equal blinded node path length");
8574 }
8575
8576 #[test]
8577 fn test_update_leaves_removal() {
8578 use crate::LeafUpdate;
8579 use alloy_primitives::map::B256Map;
8580 use std::cell::RefCell;
8581
8582 let provider = DefaultTrieNodeProvider;
8583 let mut trie = ParallelSparseTrie::default();
8584
8585 let b256_key1 = B256::with_last_byte(1);
8588 let b256_key2 = B256::with_last_byte(2);
8589 let key1 = Nibbles::unpack(b256_key1);
8590 let key2 = Nibbles::unpack(b256_key2);
8591 let value = encode_account_value(1);
8592 trie.update_leaf(key1, value.clone(), &provider).unwrap();
8593 trie.update_leaf(key2, value, &provider).unwrap();
8594
8595 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8597 updates.insert(b256_key1, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
8600 trie.update_leaves(&mut updates, |path, min_len| {
8601 proof_targets.borrow_mut().push((path, min_len));
8602 })
8603 .unwrap();
8604
8605 assert!(updates.is_empty(), "Update map should be empty after successful removal");
8607 }
8608
8609 #[test]
8610 fn test_update_leaves_removal_blinded() {
8611 use crate::LeafUpdate;
8612 use alloy_primitives::map::B256Map;
8613 use std::cell::RefCell;
8614
8615 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8618 let leaf = LeafNode::new(
8619 Nibbles::default(), small_value,
8621 );
8622 let branch = TrieNode::Branch(BranchNode::new(
8623 vec![
8624 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8627 TrieMask::new(0b11),
8628 ));
8629
8630 let mut trie = ParallelSparseTrie::from_root(
8631 branch.clone(),
8632 Some(BranchNodeMasks {
8633 hash_mask: TrieMask::new(0b01),
8634 tree_mask: TrieMask::default(),
8635 }),
8636 false,
8637 )
8638 .unwrap();
8639
8640 trie.reveal_node(
8641 Nibbles::default(),
8642 branch,
8643 Some(BranchNodeMasks {
8644 hash_mask: TrieMask::default(),
8645 tree_mask: TrieMask::new(0b01),
8646 }),
8647 )
8648 .unwrap();
8649 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), None).unwrap();
8650
8651 let b256_key = B256::ZERO; let full_path = Nibbles::unpack(b256_key);
8654
8655 let old_value = encode_account_value(99);
8657 trie.upper_subtrie.inner.values.insert(full_path, old_value.clone());
8658
8659 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8660 updates.insert(b256_key, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
8663 let prefix_set_len_before = trie.prefix_set.len();
8664 trie.update_leaves(&mut updates, |path, min_len| {
8665 proof_targets.borrow_mut().push((path, min_len));
8666 })
8667 .unwrap();
8668
8669 assert!(
8671 !proof_targets.borrow().is_empty(),
8672 "Callback should be invoked when removal hits blinded node"
8673 );
8674
8675 assert!(!updates.is_empty(), "Update should remain in map when removal hits blinded node");
8677
8678 assert_eq!(
8680 trie.upper_subtrie.inner.values.get(&full_path),
8681 Some(&old_value),
8682 "Original value should be preserved after failed removal"
8683 );
8684
8685 assert_eq!(
8687 trie.prefix_set.len(),
8688 prefix_set_len_before,
8689 "prefix_set should be unchanged after failed removal on blinded node"
8690 );
8691 }
8692
8693 #[test]
8694 fn test_update_leaves_removal_branch_collapse_blinded() {
8695 use crate::LeafUpdate;
8696 use alloy_primitives::map::B256Map;
8697 use std::cell::RefCell;
8698
8699 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8703 let leaf = LeafNode::new(Nibbles::default(), small_value);
8704 let branch = TrieNode::Branch(BranchNode::new(
8705 vec![
8706 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8709 TrieMask::new(0b11),
8710 ));
8711
8712 let mut trie = ParallelSparseTrie::from_root(
8713 branch.clone(),
8714 Some(BranchNodeMasks {
8715 hash_mask: TrieMask::new(0b01), tree_mask: TrieMask::default(),
8717 }),
8718 false,
8719 )
8720 .unwrap();
8721
8722 trie.reveal_node(
8724 Nibbles::default(),
8725 branch,
8726 Some(BranchNodeMasks {
8727 hash_mask: TrieMask::default(),
8728 tree_mask: TrieMask::new(0b01),
8729 }),
8730 )
8731 .unwrap();
8732 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), None).unwrap();
8733
8734 let b256_key = B256::with_last_byte(0x10);
8737 let full_path = Nibbles::unpack(b256_key);
8738 let leaf_value = encode_account_value(42);
8739 trie.upper_subtrie.inner.values.insert(full_path, leaf_value.clone());
8740
8741 let prefix_set_len_before = trie.prefix_set.len();
8743 let node_count_before = trie.upper_subtrie.nodes.len() +
8744 trie.lower_subtries
8745 .iter()
8746 .filter_map(|s| s.as_revealed_ref())
8747 .map(|s| s.nodes.len())
8748 .sum::<usize>();
8749
8750 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8751 updates.insert(b256_key, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
8754 trie.update_leaves(&mut updates, |path, min_len| {
8755 proof_targets.borrow_mut().push((path, min_len));
8756 })
8757 .unwrap();
8758
8759 assert!(
8761 !updates.is_empty(),
8762 "Update should remain in map when removal would collapse branch with blinded sibling"
8763 );
8764
8765 assert!(
8767 !proof_targets.borrow().is_empty(),
8768 "Callback should be invoked for blinded sibling path"
8769 );
8770
8771 assert_eq!(
8773 trie.prefix_set.len(),
8774 prefix_set_len_before,
8775 "prefix_set should be unchanged after atomic failure"
8776 );
8777
8778 let node_count_after = trie.upper_subtrie.nodes.len() +
8780 trie.lower_subtries
8781 .iter()
8782 .filter_map(|s| s.as_revealed_ref())
8783 .map(|s| s.nodes.len())
8784 .sum::<usize>();
8785 assert_eq!(
8786 node_count_before, node_count_after,
8787 "Node count should be unchanged after atomic failure"
8788 );
8789
8790 assert_eq!(
8792 trie.upper_subtrie.inner.values.get(&full_path),
8793 Some(&leaf_value),
8794 "Leaf value should still exist after failed removal"
8795 );
8796 }
8797
8798 #[test]
8799 fn test_update_leaves_touched() {
8800 use crate::LeafUpdate;
8801 use alloy_primitives::map::B256Map;
8802 use std::cell::RefCell;
8803
8804 let provider = DefaultTrieNodeProvider;
8805 let mut trie = ParallelSparseTrie::default();
8806
8807 let b256_key = B256::with_last_byte(42);
8809 let key = Nibbles::unpack(b256_key);
8810 let value = encode_account_value(1);
8811 trie.update_leaf(key, value, &provider).unwrap();
8812
8813 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8815 updates.insert(b256_key, LeafUpdate::Touched);
8816
8817 let proof_targets = RefCell::new(Vec::new());
8818 let prefix_set_len_before = trie.prefix_set.len();
8819
8820 trie.update_leaves(&mut updates, |path, min_len| {
8821 proof_targets.borrow_mut().push((path, min_len));
8822 })
8823 .unwrap();
8824
8825 assert!(updates.is_empty(), "Touched update should be removed for accessible path");
8827
8828 assert!(
8830 proof_targets.borrow().is_empty(),
8831 "Callback should not be invoked for accessible path"
8832 );
8833
8834 assert_eq!(
8836 trie.prefix_set.len(),
8837 prefix_set_len_before,
8838 "prefix_set should be unchanged for Touched update (read-only)"
8839 );
8840 }
8841
8842 #[test]
8843 fn test_update_leaves_touched_nonexistent() {
8844 use crate::LeafUpdate;
8845 use alloy_primitives::map::B256Map;
8846 use std::cell::RefCell;
8847
8848 let mut trie = ParallelSparseTrie::default();
8849
8850 let b256_key = B256::with_last_byte(99);
8852 let full_path = Nibbles::unpack(b256_key);
8853
8854 let prefix_set_len_before = trie.prefix_set.len();
8855
8856 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8857 updates.insert(b256_key, LeafUpdate::Touched);
8858
8859 let proof_targets = RefCell::new(Vec::new());
8860 trie.update_leaves(&mut updates, |path, min_len| {
8861 proof_targets.borrow_mut().push((path, min_len));
8862 })
8863 .unwrap();
8864
8865 assert!(updates.is_empty(), "Touched update should be removed for accessible (empty) path");
8867
8868 assert!(
8870 proof_targets.borrow().is_empty(),
8871 "Callback should not be invoked for accessible path"
8872 );
8873
8874 assert_eq!(
8876 trie.prefix_set.len(),
8877 prefix_set_len_before,
8878 "prefix_set should not be modified by Touched update"
8879 );
8880
8881 assert!(
8883 trie.get_leaf_value(&full_path).is_none(),
8884 "No value should exist for non-existent key after Touched update"
8885 );
8886 }
8887
8888 #[test]
8889 fn test_update_leaves_touched_blinded() {
8890 use crate::LeafUpdate;
8891 use alloy_primitives::map::B256Map;
8892 use std::cell::RefCell;
8893
8894 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8897 let leaf = LeafNode::new(
8898 Nibbles::default(), small_value,
8900 );
8901 let branch = TrieNode::Branch(BranchNode::new(
8902 vec![
8903 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8906 TrieMask::new(0b11),
8907 ));
8908
8909 let mut trie = ParallelSparseTrie::from_root(
8910 branch.clone(),
8911 Some(BranchNodeMasks {
8912 hash_mask: TrieMask::new(0b01),
8913 tree_mask: TrieMask::default(),
8914 }),
8915 false,
8916 )
8917 .unwrap();
8918
8919 trie.reveal_node(
8920 Nibbles::default(),
8921 branch,
8922 Some(BranchNodeMasks {
8923 hash_mask: TrieMask::default(),
8924 tree_mask: TrieMask::new(0b01),
8925 }),
8926 )
8927 .unwrap();
8928 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), None).unwrap();
8929
8930 let b256_key = B256::ZERO; let mut updates: B256Map<LeafUpdate> = B256Map::default();
8934 updates.insert(b256_key, LeafUpdate::Touched);
8935
8936 let proof_targets = RefCell::new(Vec::new());
8937 let prefix_set_len_before = trie.prefix_set.len();
8938 trie.update_leaves(&mut updates, |path, min_len| {
8939 proof_targets.borrow_mut().push((path, min_len));
8940 })
8941 .unwrap();
8942
8943 assert!(!proof_targets.borrow().is_empty(), "Callback should be invoked for blinded path");
8945
8946 assert!(!updates.is_empty(), "Touched update should remain in map for blinded path");
8948
8949 assert_eq!(
8951 trie.prefix_set.len(),
8952 prefix_set_len_before,
8953 "prefix_set should be unchanged for Touched update on blinded path"
8954 );
8955 }
8956
8957 #[test]
8958 fn test_update_leaves_deduplication() {
8959 use crate::LeafUpdate;
8960 use alloy_primitives::map::B256Map;
8961 use std::cell::RefCell;
8962
8963 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8966 let leaf = LeafNode::new(
8967 Nibbles::default(), small_value,
8969 );
8970 let branch = TrieNode::Branch(BranchNode::new(
8971 vec![
8972 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8975 TrieMask::new(0b11),
8976 ));
8977
8978 let mut trie = ParallelSparseTrie::from_root(
8979 branch.clone(),
8980 Some(BranchNodeMasks {
8981 hash_mask: TrieMask::new(0b01),
8982 tree_mask: TrieMask::default(),
8983 }),
8984 false,
8985 )
8986 .unwrap();
8987
8988 trie.reveal_node(
8989 Nibbles::default(),
8990 branch,
8991 Some(BranchNodeMasks {
8992 hash_mask: TrieMask::default(),
8993 tree_mask: TrieMask::new(0b01),
8994 }),
8995 )
8996 .unwrap();
8997 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNode::Leaf(leaf), None).unwrap();
8998
8999 let b256_key1 = B256::ZERO;
9002 let b256_key2 = B256::with_last_byte(1); let b256_key3 = B256::with_last_byte(2); let mut updates: B256Map<LeafUpdate> = B256Map::default();
9006 let value = encode_account_value(42);
9007
9008 updates.insert(b256_key1, LeafUpdate::Changed(value.clone()));
9009 updates.insert(b256_key2, LeafUpdate::Changed(value.clone()));
9010 updates.insert(b256_key3, LeafUpdate::Changed(value));
9011
9012 let proof_targets = RefCell::new(Vec::new());
9013 trie.update_leaves(&mut updates, |path, min_len| {
9014 proof_targets.borrow_mut().push((path, min_len));
9015 })
9016 .unwrap();
9017
9018 let targets = proof_targets.borrow();
9021 assert_eq!(targets.len(), 3, "Callback should be invoked for each unique key");
9022
9023 for (_, min_len) in targets.iter() {
9025 assert_eq!(*min_len, 1, "All should have min_len 1 from blinded node at 0x0");
9026 }
9027 }
9028
9029 #[test]
9030 fn test_update_leaves_node_not_found_in_provider_atomicity() {
9031 use crate::LeafUpdate;
9032 use alloy_primitives::map::B256Map;
9033 use std::cell::RefCell;
9034
9035 let child_hash = B256::repeat_byte(0xAB);
9044 let extension = TrieNode::Extension(ExtensionNode::new(
9045 Nibbles::from_nibbles([0x1, 0x2, 0x3]),
9046 RlpNode::word_rlp(&child_hash),
9047 ));
9048
9049 let mut trie =
9051 ParallelSparseTrie::from_root(extension, None, true).expect("from_root failed");
9052
9053 let prefix_set_len_before = trie.prefix_set.len();
9055 let node_count_before = trie.upper_subtrie.nodes.len() +
9056 trie.lower_subtries
9057 .iter()
9058 .filter_map(|s| s.as_revealed_ref())
9059 .map(|s| s.nodes.len())
9060 .sum::<usize>();
9061 let value_count_before = trie.upper_subtrie.inner.values.len() +
9062 trie.lower_subtries
9063 .iter()
9064 .filter_map(|s| s.as_revealed_ref())
9065 .map(|s| s.inner.values.len())
9066 .sum::<usize>();
9067
9068 let b256_key = {
9071 let mut k = B256::ZERO;
9072 k.0[0] = 0x14; k
9074 };
9075
9076 let new_value = encode_account_value(42);
9077 let mut updates: B256Map<LeafUpdate> = B256Map::default();
9078 updates.insert(b256_key, LeafUpdate::Changed(new_value));
9079
9080 let proof_targets = RefCell::new(Vec::new());
9081 trie.update_leaves(&mut updates, |path, min_len| {
9082 proof_targets.borrow_mut().push((path, min_len));
9083 })
9084 .expect("update_leaves should succeed");
9085
9086 assert!(
9088 !updates.is_empty(),
9089 "Update should remain in map when NodeNotFoundInProvider occurs"
9090 );
9091 assert!(
9092 updates.contains_key(&b256_key),
9093 "The specific key should be re-inserted for retry"
9094 );
9095
9096 let targets = proof_targets.borrow();
9098 assert!(!targets.is_empty(), "Callback should be invoked for NodeNotFoundInProvider");
9099
9100 assert_eq!(
9102 trie.prefix_set.len(),
9103 prefix_set_len_before,
9104 "prefix_set should be unchanged after atomic failure"
9105 );
9106
9107 let node_count_after = trie.upper_subtrie.nodes.len() +
9109 trie.lower_subtries
9110 .iter()
9111 .filter_map(|s| s.as_revealed_ref())
9112 .map(|s| s.nodes.len())
9113 .sum::<usize>();
9114 assert_eq!(
9115 node_count_before, node_count_after,
9116 "Node count should be unchanged after atomic failure"
9117 );
9118
9119 let value_count_after = trie.upper_subtrie.inner.values.len() +
9121 trie.lower_subtries
9122 .iter()
9123 .filter_map(|s| s.as_revealed_ref())
9124 .map(|s| s.inner.values.len())
9125 .sum::<usize>();
9126 assert_eq!(
9127 value_count_before, value_count_after,
9128 "Value count should be unchanged after atomic failure (no dangling values)"
9129 );
9130 }
9131
9132 #[test]
9133 fn test_nibbles_to_padded_b256() {
9134 let empty = Nibbles::default();
9136 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&empty), B256::ZERO);
9137
9138 let full_key = b256!("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
9140 let full_nibbles = Nibbles::unpack(full_key);
9141 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&full_nibbles), full_key);
9142
9143 let partial = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
9146 let expected = b256!("1234000000000000000000000000000000000000000000000000000000000000");
9147 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&partial), expected);
9148
9149 let single = Nibbles::from_nibbles_unchecked([0xf]);
9151 let expected_single =
9152 b256!("f000000000000000000000000000000000000000000000000000000000000000");
9153 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&single), expected_single);
9154 }
9155
9156 #[test]
9157 fn test_memory_size() {
9158 let trie = ParallelSparseTrie::default();
9160 let empty_size = trie.memory_size();
9161
9162 assert!(empty_size >= core::mem::size_of::<ParallelSparseTrie>());
9164
9165 let root_branch = create_branch_node_with_children(
9169 &[0x1, 0x5],
9170 [
9171 RlpNode::word_rlp(&B256::repeat_byte(0xAA)),
9172 RlpNode::word_rlp(&B256::repeat_byte(0xBB)),
9173 ],
9174 );
9175 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
9176
9177 let branch_at_1 =
9178 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xCC))]);
9179 let branch_at_5 =
9180 create_branch_node_with_children(&[0x6], [RlpNode::word_rlp(&B256::repeat_byte(0xDD))]);
9181 trie.reveal_nodes(&mut [
9182 ProofTrieNode {
9183 path: Nibbles::from_nibbles_unchecked([0x1]),
9184 node: branch_at_1,
9185 masks: None,
9186 },
9187 ProofTrieNode {
9188 path: Nibbles::from_nibbles_unchecked([0x5]),
9189 node: branch_at_5,
9190 masks: None,
9191 },
9192 ])
9193 .unwrap();
9194
9195 let mut nodes = vec![
9196 ProofTrieNode {
9197 path: Nibbles::from_nibbles_unchecked([0x1, 0x2]),
9198 node: TrieNode::Leaf(LeafNode {
9199 key: Nibbles::from_nibbles_unchecked([0x3, 0x4]),
9200 value: vec![1, 2, 3],
9201 }),
9202 masks: None,
9203 },
9204 ProofTrieNode {
9205 path: Nibbles::from_nibbles_unchecked([0x5, 0x6]),
9206 node: TrieNode::Leaf(LeafNode {
9207 key: Nibbles::from_nibbles_unchecked([0x7, 0x8]),
9208 value: vec![4, 5, 6],
9209 }),
9210 masks: None,
9211 },
9212 ];
9213 trie.reveal_nodes(&mut nodes).unwrap();
9214
9215 let populated_size = trie.memory_size();
9216
9217 assert!(populated_size > empty_size);
9219 }
9220}