1#[cfg(feature = "trie-debug")]
2use crate::debug_recorder::{LeafUpdateRecord, ProofTrieNodeRecord, RecordedOp, TrieDebugRecorder};
3use crate::{
4 lower::LowerSparseSubtrie, LeafLookup, LeafLookupError, RlpNodeStackItem, SparseNode,
5 SparseNodeState, SparseNodeType, SparseTrie, SparseTrieUpdates,
6};
7use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};
8use alloy_primitives::{
9 map::{Entry, HashMap, HashSet},
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};
16#[cfg(feature = "metrics")]
17use reth_primitives_traits::FastInstant as Instant;
18use reth_trie_common::{
19 prefix_set::{PrefixSet, PrefixSetMut},
20 BranchNodeMasks, BranchNodeMasksMap, BranchNodeRef, ExtensionNodeRef, LeafNodeRef, Nibbles,
21 ProofTrieNodeV2, RlpNode, TrieNodeV2,
22};
23use smallvec::SmallVec;
24use tracing::{instrument, trace};
25
26pub const UPPER_TRIE_MAX_DEPTH: usize = 2;
29
30pub const NUM_LOWER_SUBTRIES: usize = 16usize.pow(UPPER_TRIE_MAX_DEPTH as u32);
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
35pub struct ParallelismThresholds {
36 pub min_revealed_nodes: usize,
39 pub min_updated_nodes: usize,
43}
44
45#[derive(Clone, PartialEq, Eq, Debug)]
107pub struct ParallelSparseTrie {
108 upper_subtrie: Box<SparseSubtrie>,
110 lower_subtries: Box<[LowerSparseSubtrie; NUM_LOWER_SUBTRIES]>,
112 prefix_set: PrefixSetMut,
115 updates: Option<SparseTrieUpdates>,
117 branch_node_masks: BranchNodeMasksMap,
123 update_actions_buffers: Vec<Vec<SparseTrieUpdatesAction>>,
126 parallelism_thresholds: ParallelismThresholds,
128 #[cfg(feature = "metrics")]
130 metrics: crate::metrics::ParallelSparseTrieMetrics,
131 #[cfg(feature = "trie-debug")]
133 debug_recorder: TrieDebugRecorder,
134}
135
136impl Default for ParallelSparseTrie {
137 fn default() -> Self {
138 Self {
139 upper_subtrie: Box::new(SparseSubtrie {
140 nodes: HashMap::from_iter([(Nibbles::default(), SparseNode::Empty)]),
141 ..Default::default()
142 }),
143 lower_subtries: Box::new(
144 [const { LowerSparseSubtrie::Blind(None) }; NUM_LOWER_SUBTRIES],
145 ),
146 prefix_set: PrefixSetMut::default(),
147 updates: None,
148 branch_node_masks: BranchNodeMasksMap::default(),
149 update_actions_buffers: Vec::default(),
150 parallelism_thresholds: Default::default(),
151 #[cfg(feature = "metrics")]
152 metrics: Default::default(),
153 #[cfg(feature = "trie-debug")]
154 debug_recorder: Default::default(),
155 }
156 }
157}
158
159impl SparseTrie for ParallelSparseTrie {
160 fn set_root(
161 &mut self,
162 root: TrieNodeV2,
163 masks: Option<BranchNodeMasks>,
164 retain_updates: bool,
165 ) -> SparseTrieResult<()> {
166 #[cfg(feature = "trie-debug")]
167 self.debug_recorder.record(RecordedOp::SetRoot {
168 node: ProofTrieNodeRecord::from_proof_trie_node_v2(&ProofTrieNodeV2 {
169 path: Nibbles::default(),
170 node: root.clone(),
171 masks,
172 }),
173 });
174
175 let path = Nibbles::default();
178 let _removed_root = self.upper_subtrie.nodes.remove(&path).expect("root node should exist");
179 debug_assert_eq!(_removed_root, SparseNode::Empty);
180
181 self.set_updates(retain_updates);
182
183 if let Some(masks) = masks {
184 let branch_path = if let TrieNodeV2::Branch(branch) = &root {
185 branch.key
186 } else {
187 Nibbles::default()
188 };
189
190 self.branch_node_masks.insert(branch_path, masks);
191 }
192
193 self.reveal_upper_node(Nibbles::default(), &root, masks)
194 }
195
196 fn set_updates(&mut self, retain_updates: bool) {
197 self.updates = retain_updates.then(Default::default);
198 }
199
200 fn reveal_nodes(&mut self, nodes: &mut [ProofTrieNodeV2]) -> SparseTrieResult<()> {
201 if nodes.is_empty() {
202 return Ok(())
203 }
204
205 #[cfg(feature = "trie-debug")]
206 self.debug_recorder.record(RecordedOp::RevealNodes {
207 nodes: nodes.iter().map(ProofTrieNodeRecord::from_proof_trie_node_v2).collect(),
208 });
209
210 nodes.sort_unstable_by(
213 |ProofTrieNodeV2 { path: path_a, .. }, ProofTrieNodeV2 { path: path_b, .. }| {
214 let subtrie_type_a = SparseSubtrieType::from_path(path_a);
215 let subtrie_type_b = SparseSubtrieType::from_path(path_b);
216 subtrie_type_a.cmp(&subtrie_type_b).then_with(|| path_a.cmp(path_b))
217 },
218 );
219
220 self.branch_node_masks.reserve(nodes.len());
222 for ProofTrieNodeV2 { path, masks, node } in nodes.iter() {
223 if let Some(branch_masks) = masks {
224 let path = if let TrieNodeV2::Branch(branch) = node &&
226 !branch.key.is_empty()
227 {
228 let mut path = *path;
229 path.extend(&branch.key);
230 path
231 } else {
232 *path
233 };
234 self.branch_node_masks.insert(path, *branch_masks);
235 }
236 }
237
238 let num_upper_nodes = nodes
242 .iter()
243 .position(|n| !SparseSubtrieType::path_len_is_upper(n.path.len()))
244 .unwrap_or(nodes.len());
245 let (upper_nodes, lower_nodes) = nodes.split_at(num_upper_nodes);
246
247 self.upper_subtrie.nodes.reserve(upper_nodes.len());
250 for node in upper_nodes {
251 self.reveal_upper_node(node.path, &node.node, node.masks)?;
252 }
253
254 let reachable_subtries = self.reachable_subtries();
255
256 let hashes_from_upper = nodes
261 .iter()
262 .filter_map(|node| {
263 if node.path.len() != UPPER_TRIE_MAX_DEPTH ||
264 !reachable_subtries.get(path_subtrie_index_unchecked(&node.path))
265 {
266 return None;
267 }
268
269 let parent_path = node.path.slice(0..UPPER_TRIE_MAX_DEPTH - 1);
270 let Some(SparseNode::Branch { blinded_mask, blinded_hashes, .. }) =
271 self.upper_subtrie.nodes.get_mut(&parent_path)
272 else {
273 return None;
274 };
275
276 let nibble = node.path.last().unwrap();
277 blinded_mask.is_bit_set(nibble).then(|| {
278 blinded_mask.unset_bit(nibble);
279 (node.path, blinded_hashes[nibble as usize])
280 })
281 })
282 .collect::<HashMap<_, _>>();
283
284 if !self.is_reveal_parallelism_enabled(lower_nodes.len()) {
285 for node in lower_nodes {
286 let idx = path_subtrie_index_unchecked(&node.path);
287 if !reachable_subtries.get(idx) {
288 trace!(
289 target: "trie::parallel_sparse",
290 reveal_path = ?node.path,
291 "Node's lower subtrie is not reachable, skipping",
292 );
293 continue;
294 }
295 if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
297 !Self::is_boundary_leaf_reachable(
298 &self.upper_subtrie.nodes,
299 &node.path,
300 &node.node,
301 )
302 {
303 trace!(
304 target: "trie::parallel_sparse",
305 path = ?node.path,
306 "Boundary leaf not reachable from upper subtrie, skipping",
307 );
308 continue;
309 }
310 self.lower_subtries[idx].reveal(&node.path);
311 self.lower_subtries[idx].as_revealed_mut().expect("just revealed").reveal_node(
312 node.path,
313 &node.node,
314 node.masks,
315 hashes_from_upper.get(&node.path).copied(),
316 )?;
317 }
318 return Ok(())
319 }
320
321 #[cfg(not(feature = "std"))]
322 unreachable!("nostd is checked by is_reveal_parallelism_enabled");
323
324 #[cfg(feature = "std")]
325 {
327 use rayon::iter::{IntoParallelIterator, ParallelIterator};
328 use tracing::Span;
329
330 let parent_span = Span::current();
332
333 let upper_nodes = &self.upper_subtrie.nodes;
335
336 let results = lower_nodes
338 .chunk_by(|node_a, node_b| {
339 SparseSubtrieType::from_path(&node_a.path) ==
340 SparseSubtrieType::from_path(&node_b.path)
341 })
342 .filter_map(|nodes| {
344 let mut nodes = nodes
345 .iter()
346 .filter(|node| {
347 if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
350 !Self::is_boundary_leaf_reachable(
351 upper_nodes,
352 &node.path,
353 &node.node,
354 )
355 {
356 trace!(
357 target: "trie::parallel_sparse",
358 path = ?node.path,
359 "Boundary leaf not reachable from upper subtrie, skipping",
360 );
361 false
362 } else {
363 true
364 }
365 })
366 .peekable();
367
368 let node = nodes.peek()?;
369 let idx =
370 SparseSubtrieType::from_path(&node.path).lower_index().unwrap_or_else(
371 || panic!("upper subtrie node {node:?} found amongst lower nodes"),
372 );
373
374 if !reachable_subtries.get(idx) {
375 trace!(
376 target: "trie::parallel_sparse",
377 nodes = ?nodes,
378 "Lower subtrie is not reachable, skipping reveal",
379 );
380 return None;
381 }
382
383 self.lower_subtries[idx].reveal(&node.path);
388 Some((
389 idx,
390 self.lower_subtries[idx].take_revealed().expect("just revealed"),
391 nodes,
392 ))
393 })
394 .collect::<Vec<_>>()
395 .into_par_iter()
396 .map(|(subtrie_idx, mut subtrie, nodes)| {
397 let _guard = parent_span.enter();
400
401 subtrie.nodes.reserve(nodes.size_hint().1.unwrap_or(0));
404
405 for node in nodes {
406 let res = subtrie.reveal_node(
408 node.path,
409 &node.node,
410 node.masks,
411 hashes_from_upper.get(&node.path).copied(),
412 );
413 if res.is_err() {
414 return (subtrie_idx, subtrie, res.map(|_| ()))
415 }
416 }
417 (subtrie_idx, subtrie, Ok(()))
418 })
419 .collect::<Vec<_>>();
420
421 let mut any_err = Ok(());
424 for (subtrie_idx, subtrie, res) in results {
425 self.lower_subtries[subtrie_idx] = LowerSparseSubtrie::Revealed(subtrie);
426 if res.is_err() {
427 any_err = res;
428 }
429 }
430
431 any_err
432 }
433 }
434
435 #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
436 fn root(&mut self) -> B256 {
437 trace!(target: "trie::parallel_sparse", "Calculating trie root hash");
438
439 #[cfg(feature = "trie-debug")]
440 self.debug_recorder.record(RecordedOp::Root);
441
442 if self.prefix_set.is_empty() &&
443 let Some(rlp_node) = self
444 .upper_subtrie
445 .nodes
446 .get(&Nibbles::default())
447 .and_then(|node| node.cached_rlp_node())
448 {
449 return rlp_node
450 .as_hash()
451 .expect("RLP-encoding of the root node cannot be less than 32 bytes")
452 }
453
454 self.update_subtrie_hashes();
456
457 let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
460 let root_rlp = self.update_upper_subtrie_hashes(&mut prefix_set);
461
462 root_rlp.as_hash().unwrap_or(EMPTY_ROOT_HASH)
464 }
465
466 fn is_root_cached(&self) -> bool {
467 self.prefix_set.is_empty() &&
468 self.upper_subtrie
469 .nodes
470 .get(&Nibbles::default())
471 .is_some_and(|node| node.cached_rlp_node().is_some())
472 }
473
474 #[instrument(level = "trace", target = "trie::sparse::parallel", skip(self))]
475 fn update_subtrie_hashes(&mut self) {
476 trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
477
478 #[cfg(feature = "trie-debug")]
479 self.debug_recorder.record(RecordedOp::UpdateSubtrieHashes);
480
481 let mut prefix_set = core::mem::take(&mut self.prefix_set).freeze();
483 let num_changed_keys = prefix_set.len();
484 let (mut changed_subtries, unchanged_prefix_set) =
485 self.take_changed_lower_subtries(&mut prefix_set);
486
487 #[cfg(feature = "metrics")]
489 self.metrics.subtries_updated.record(changed_subtries.len() as f64);
490
491 self.prefix_set = unchanged_prefix_set;
493
494 if !self.is_update_parallelism_enabled(num_changed_keys) {
496 for changed_subtrie in &mut changed_subtries {
497 changed_subtrie.subtrie.update_hashes(
498 &mut changed_subtrie.prefix_set,
499 &mut changed_subtrie.update_actions_buf,
500 &self.branch_node_masks,
501 );
502 }
503
504 self.insert_changed_subtries(changed_subtries);
505 return
506 }
507
508 #[cfg(not(feature = "std"))]
509 unreachable!("nostd is checked by is_update_parallelism_enabled");
510
511 #[cfg(feature = "std")]
512 {
514 use rayon::prelude::*;
515
516 changed_subtries.par_iter_mut().for_each(|changed_subtrie| {
517 #[cfg(feature = "metrics")]
518 let start = Instant::now();
519 changed_subtrie.subtrie.update_hashes(
520 &mut changed_subtrie.prefix_set,
521 &mut changed_subtrie.update_actions_buf,
522 &self.branch_node_masks,
523 );
524 #[cfg(feature = "metrics")]
525 self.metrics.subtrie_hash_update_latency.record(start.elapsed());
526 });
527
528 self.insert_changed_subtries(changed_subtries);
529 }
530 }
531
532 fn get_leaf_value(&self, full_path: &Nibbles) -> Option<&Vec<u8>> {
533 if let Some(subtrie) = self.subtrie_for_path(full_path) &&
538 !subtrie.is_empty()
539 {
540 return subtrie.inner.values.get(full_path);
541 }
542
543 self.upper_subtrie.inner.values.get(full_path)
544 }
545
546 fn updates_ref(&self) -> Cow<'_, SparseTrieUpdates> {
547 self.updates.as_ref().map_or(Cow::Owned(SparseTrieUpdates::default()), Cow::Borrowed)
548 }
549
550 fn take_updates(&mut self) -> SparseTrieUpdates {
551 match self.updates.take() {
552 Some(updates) => {
553 self.updates = Some(SparseTrieUpdates::with_capacity(
555 updates.updated_nodes.len(),
556 updates.removed_nodes.len(),
557 ));
558 updates
559 }
560 None => SparseTrieUpdates::default(),
561 }
562 }
563
564 fn wipe(&mut self) {
565 self.upper_subtrie.wipe();
566 for trie in &mut *self.lower_subtries {
567 trie.wipe();
568 }
569 self.prefix_set = PrefixSetMut::all();
570 self.updates = self.updates.is_some().then(SparseTrieUpdates::wiped);
571 }
572
573 fn clear(&mut self) {
574 self.upper_subtrie.clear();
575 self.upper_subtrie.nodes.insert(Nibbles::default(), SparseNode::Empty);
576 for subtrie in &mut *self.lower_subtries {
577 subtrie.clear();
578 }
579 self.prefix_set.clear();
580 self.updates = None;
581 self.branch_node_masks.clear();
582 #[cfg(feature = "trie-debug")]
583 self.debug_recorder.reset();
584 }
587
588 fn find_leaf(
589 &self,
590 full_path: &Nibbles,
591 expected_value: Option<&Vec<u8>>,
592 ) -> Result<LeafLookup, LeafLookupError> {
593 if let Some(actual_value) = core::iter::once(self.upper_subtrie.as_ref())
599 .chain(self.lower_subtrie_for_path(full_path))
600 .filter_map(|subtrie| subtrie.inner.values.get(full_path))
601 .next()
602 {
603 return expected_value
605 .is_none_or(|v| v == actual_value)
606 .then_some(LeafLookup::Exists)
607 .ok_or_else(|| LeafLookupError::ValueMismatch {
608 path: *full_path,
609 expected: expected_value.cloned(),
610 actual: actual_value.clone(),
611 })
612 }
613
614 let mut curr_path = Nibbles::new(); let mut curr_subtrie = self.upper_subtrie.as_ref();
622 let mut curr_subtrie_is_upper = true;
623
624 loop {
625 match curr_subtrie.nodes.get(&curr_path).unwrap() {
626 SparseNode::Empty => return Ok(LeafLookup::NonExistent),
627 SparseNode::Leaf { key, .. } => {
628 let mut found_full_path = curr_path;
629 found_full_path.extend(key);
630 assert!(&found_full_path != full_path, "target leaf {full_path:?} found, even though value wasn't in values hashmap");
631 return Ok(LeafLookup::NonExistent)
632 }
633 SparseNode::Extension { key, .. } => {
634 if full_path.len() == curr_path.len() {
635 return Ok(LeafLookup::NonExistent)
636 }
637 curr_path.extend(key);
638 if !full_path.starts_with(&curr_path) {
639 return Ok(LeafLookup::NonExistent)
640 }
641 }
642 SparseNode::Branch { state_mask, blinded_mask, blinded_hashes, .. } => {
643 if full_path.len() == curr_path.len() {
644 return Ok(LeafLookup::NonExistent)
645 }
646 let nibble = full_path.get_unchecked(curr_path.len());
647 if !state_mask.is_bit_set(nibble) {
648 return Ok(LeafLookup::NonExistent)
649 }
650 curr_path.push_unchecked(nibble);
651 if blinded_mask.is_bit_set(nibble) {
652 return Err(LeafLookupError::BlindedNode {
653 path: curr_path,
654 hash: blinded_hashes[nibble as usize],
655 })
656 }
657 }
658 }
659
660 if curr_subtrie_is_upper &&
663 let Some(lower_subtrie) = self.lower_subtrie_for_path(&curr_path)
664 {
665 curr_subtrie = lower_subtrie;
666 curr_subtrie_is_upper = false;
667 }
668 }
669 }
670
671 fn shrink_nodes_to(&mut self, size: usize) {
672 let total_subtries = 1 + NUM_LOWER_SUBTRIES;
676 let size_per_subtrie = size / total_subtries;
677
678 self.upper_subtrie.shrink_nodes_to(size_per_subtrie);
680
681 for subtrie in &mut *self.lower_subtries {
683 subtrie.shrink_nodes_to(size_per_subtrie);
684 }
685
686 self.branch_node_masks.shrink_to(size);
688 }
689
690 fn shrink_values_to(&mut self, size: usize) {
691 let total_subtries = 1 + NUM_LOWER_SUBTRIES;
695 let size_per_subtrie = size / total_subtries;
696
697 self.upper_subtrie.shrink_values_to(size_per_subtrie);
699
700 for subtrie in &mut *self.lower_subtries {
702 subtrie.shrink_values_to(size_per_subtrie);
703 }
704 }
705
706 fn size_hint(&self) -> usize {
708 let upper_count = self.upper_subtrie.nodes.len();
709 let lower_count: usize = self
710 .lower_subtries
711 .iter()
712 .filter_map(|s| s.as_revealed_ref())
713 .map(|s| s.nodes.len())
714 .sum();
715 upper_count + lower_count
716 }
717
718 fn memory_size(&self) -> usize {
719 self.memory_size()
720 }
721
722 fn prune(&mut self, retained_leaves: &[Nibbles]) -> usize {
723 #[cfg(feature = "trie-debug")]
724 self.debug_recorder.reset();
725
726 let mut retained_leaves = retained_leaves.to_vec();
727 retained_leaves.sort_unstable();
728
729 let mut effective_pruned_roots = Vec::<Nibbles>::new();
730 let mut stack: SmallVec<[Nibbles; 32]> = SmallVec::new();
731 stack.push(Nibbles::default());
732
733 while let Some(path) = stack.pop() {
734 let Some(node) =
735 self.subtrie_for_path(&path).and_then(|subtrie| subtrie.nodes.get(&path).cloned())
736 else {
737 continue;
738 };
739
740 match node {
741 SparseNode::Empty | SparseNode::Leaf { .. } => {}
742 SparseNode::Extension { key, state, .. } => {
743 let mut child = path;
744 child.extend(&key);
745
746 if has_retained_descendant(&retained_leaves, &child) {
747 stack.push(child);
748 continue;
749 }
750
751 if path.is_empty() {
753 continue;
754 }
755
756 let Some(hash) = state.cached_hash() else { continue };
757 self.subtrie_for_path_mut_untracked(&path)
758 .expect("node subtrie exists")
759 .nodes
760 .remove(&path);
761
762 let parent_path = path.slice(0..path.len() - 1);
763 let SparseNode::Branch { blinded_mask, blinded_hashes, .. } = self
766 .subtrie_for_path_mut_untracked(&parent_path)
767 .expect("parent subtrie exists")
768 .nodes
769 .get_mut(&parent_path)
770 .expect("expected parent branch node")
771 else {
772 panic!("expected branch node at path {parent_path:?}");
773 };
774
775 let nibble = path.last().unwrap();
776 blinded_mask.set_bit(nibble);
777 blinded_hashes[nibble as usize] = hash;
778 effective_pruned_roots.push(path);
779 }
780 SparseNode::Branch { state_mask, blinded_mask, blinded_hashes, .. } => {
781 let mut blinded_mask = blinded_mask;
782 let mut blinded_hashes = blinded_hashes;
783 for nibble in state_mask.iter() {
784 if blinded_mask.is_bit_set(nibble) {
785 continue;
786 }
787
788 let mut child = path;
789 child.push_unchecked(nibble);
790 if has_retained_descendant(&retained_leaves, &child) {
791 stack.push(child);
792 continue;
793 }
794
795 let Entry::Occupied(entry) =
796 self.subtrie_for_path_mut_untracked(&child).unwrap().nodes.entry(child)
797 else {
798 panic!("expected node at path {child:?}");
799 };
800
801 let Some(hash) = entry.get().cached_hash() else {
802 continue;
803 };
804 entry.remove();
805 blinded_mask.set_bit(nibble);
806 blinded_hashes[nibble as usize] = hash;
807 effective_pruned_roots.push(child);
808 }
809
810 let SparseNode::Branch {
811 blinded_mask: old_blinded_mask,
812 blinded_hashes: old_blinded_hashes,
813 ..
814 } = self
815 .subtrie_for_path_mut_untracked(&path)
816 .unwrap()
817 .nodes
818 .get_mut(&path)
819 .unwrap()
820 else {
821 unreachable!("expected branch node at path {path:?}");
822 };
823 *old_blinded_mask = blinded_mask;
824 *old_blinded_hashes = blinded_hashes;
825 }
826 }
827 }
828
829 Self::finalize_pruned_roots(self, effective_pruned_roots)
830 }
831
832 fn update_leaves(
833 &mut self,
834 updates: &mut alloy_primitives::map::B256Map<crate::LeafUpdate>,
835 mut proof_required_fn: impl FnMut(B256, u8),
836 ) -> SparseTrieResult<()> {
837 use crate::LeafUpdate;
838
839 #[cfg(feature = "trie-debug")]
840 let recorded_updates: Vec<_> =
841 updates.iter().map(|(k, v)| (*k, LeafUpdateRecord::from(v))).collect();
842 #[cfg(feature = "trie-debug")]
843 let mut recorded_proof_targets: Vec<(B256, u8)> = Vec::new();
844
845 let drained: Vec<_> = updates.drain().collect();
848
849 for (key, update) in drained {
850 let full_path = Nibbles::unpack(key);
851
852 match update {
853 LeafUpdate::Changed(value) => {
854 if value.is_empty() {
855 match self.remove_leaf(&full_path) {
858 Ok(()) => {}
859 Err(e) => {
860 if let Some(path) = Self::get_retriable_path(&e) {
861 let (target_key, min_len) =
862 Self::proof_target_for_path(key, &full_path, &path);
863 proof_required_fn(target_key, min_len);
864 #[cfg(feature = "trie-debug")]
865 recorded_proof_targets.push((target_key, min_len));
866 updates.insert(key, LeafUpdate::Changed(value));
867 } else {
868 return Err(e);
869 }
870 }
871 }
872 } else {
873 if let Err(e) = self.update_leaf(full_path, value.clone()) {
875 if let Some(path) = Self::get_retriable_path(&e) {
876 let (target_key, min_len) =
877 Self::proof_target_for_path(key, &full_path, &path);
878 proof_required_fn(target_key, min_len);
879 #[cfg(feature = "trie-debug")]
880 recorded_proof_targets.push((target_key, min_len));
881 updates.insert(key, LeafUpdate::Changed(value));
882 } else {
883 return Err(e);
884 }
885 }
886 }
887 }
888 LeafUpdate::Touched => {
889 match self.find_leaf(&full_path, None) {
891 Err(LeafLookupError::BlindedNode { path, .. }) => {
892 let (target_key, min_len) =
893 Self::proof_target_for_path(key, &full_path, &path);
894 proof_required_fn(target_key, min_len);
895 #[cfg(feature = "trie-debug")]
896 recorded_proof_targets.push((target_key, min_len));
897 updates.insert(key, LeafUpdate::Touched);
898 }
899 Ok(_) | Err(LeafLookupError::ValueMismatch { .. }) => {}
901 }
902 }
903 }
904 }
905
906 #[cfg(feature = "trie-debug")]
907 self.debug_recorder.record(RecordedOp::UpdateLeaves {
908 updates: recorded_updates,
909 proof_targets: recorded_proof_targets,
910 });
911
912 Ok(())
913 }
914
915 #[cfg(feature = "trie-debug")]
916 fn take_debug_recorder(&mut self) -> TrieDebugRecorder {
917 core::mem::take(&mut self.debug_recorder)
918 }
919
920 fn commit_updates(
921 &mut self,
922 updated: &HashMap<Nibbles, BranchNodeCompact>,
923 removed: &HashSet<Nibbles>,
924 ) {
925 self.branch_node_masks.reserve(updated.len());
929 for (path, node) in updated {
930 self.branch_node_masks.insert(
931 *path,
932 BranchNodeMasks { tree_mask: node.tree_mask, hash_mask: node.hash_mask },
933 );
934 }
935 for path in removed {
936 self.branch_node_masks.remove(path);
937 }
938 }
939}
940
941impl ParallelSparseTrie {
942 pub const fn with_parallelism_thresholds(mut self, thresholds: ParallelismThresholds) -> Self {
944 self.parallelism_thresholds = thresholds;
945 self
946 }
947
948 const fn updates_enabled(&self) -> bool {
950 self.updates.is_some()
951 }
952
953 const fn is_reveal_parallelism_enabled(&self, num_nodes: usize) -> bool {
956 #[cfg(not(feature = "std"))]
957 {
958 let _ = num_nodes;
959 false
960 }
961
962 #[cfg(feature = "std")]
963 {
964 num_nodes >= self.parallelism_thresholds.min_revealed_nodes
965 }
966 }
967
968 const fn is_update_parallelism_enabled(&self, num_changed_keys: usize) -> bool {
971 #[cfg(not(feature = "std"))]
972 {
973 let _ = num_changed_keys;
974 false
975 }
976
977 #[cfg(feature = "std")]
978 {
979 num_changed_keys >= self.parallelism_thresholds.min_updated_nodes
980 }
981 }
982
983 const fn get_retriable_path(e: &SparseTrieError) -> Option<Nibbles> {
990 match e.kind() {
991 SparseTrieErrorKind::BlindedNode(path) |
992 SparseTrieErrorKind::NodeNotFoundInProvider { path } => Some(*path),
993 _ => None,
994 }
995 }
996
997 fn nibbles_to_padded_b256(path: &Nibbles) -> B256 {
999 let mut bytes = [0u8; 32];
1000 path.pack_to(&mut bytes);
1001 B256::from(bytes)
1002 }
1003
1004 fn proof_target_for_path(full_key: B256, full_path: &Nibbles, path: &Nibbles) -> (B256, u8) {
1010 let min_len = (path.len() as u8).min(64);
1011 let target_key =
1012 if full_path.starts_with(path) { full_key } else { Self::nibbles_to_padded_b256(path) };
1013 (target_key, min_len)
1014 }
1015
1016 pub fn from_root(
1031 root: TrieNodeV2,
1032 masks: Option<BranchNodeMasks>,
1033 retain_updates: bool,
1034 ) -> SparseTrieResult<Self> {
1035 Self::default().with_root(root, masks, retain_updates)
1036 }
1037
1038 pub fn update_leaf(&mut self, full_path: Nibbles, value: Vec<u8>) -> SparseTrieResult<()> {
1040 debug_assert_eq!(
1041 full_path.len(),
1042 B256::len_bytes() * 2,
1043 "update_leaf full_path must be 64 nibbles (32 bytes), got {} nibbles",
1044 full_path.len()
1045 );
1046
1047 trace!(
1048 target: "trie::parallel_sparse",
1049 ?full_path,
1050 value_len = value.len(),
1051 "Updating leaf",
1052 );
1053
1054 if self.upper_subtrie.inner.values.contains_key(&full_path) {
1055 self.prefix_set.insert(full_path);
1056 self.upper_subtrie.inner.values.insert(full_path, value);
1057 return Ok(());
1058 }
1059 if let Some(subtrie) = self.lower_subtrie_for_path(&full_path) &&
1060 subtrie.inner.values.contains_key(&full_path)
1061 {
1062 self.prefix_set.insert(full_path);
1063 self.lower_subtrie_for_path_mut(&full_path)
1064 .expect("subtrie exists")
1065 .inner
1066 .values
1067 .insert(full_path, value);
1068 return Ok(());
1069 }
1070
1071 self.upper_subtrie.inner.values.insert(full_path, value.clone());
1072
1073 let mut new_nodes = Vec::new();
1074 let mut next = Some(Nibbles::default());
1075
1076 while let Some(current) =
1077 next.as_mut().filter(|next| SparseSubtrieType::path_len_is_upper(next.len()))
1078 {
1079 let step_result = self.upper_subtrie.update_next_node(current, &full_path);
1080
1081 if step_result.is_err() {
1082 self.upper_subtrie.inner.values.remove(&full_path);
1083 return step_result.map(|_| ());
1084 }
1085
1086 match step_result? {
1087 LeafUpdateStep::Continue => {}
1088 LeafUpdateStep::Complete { inserted_nodes } => {
1089 new_nodes.extend(inserted_nodes);
1090 next = None;
1091 }
1092 LeafUpdateStep::NodeNotFound => {
1093 next = None;
1094 }
1095 }
1096 }
1097
1098 for node_path in &new_nodes {
1099 if SparseSubtrieType::path_len_is_upper(node_path.len()) {
1100 continue;
1101 }
1102
1103 let node =
1104 self.upper_subtrie.nodes.remove(node_path).expect("node belongs to upper subtrie");
1105
1106 let leaf_value = if let SparseNode::Leaf { key, .. } = &node {
1107 let mut leaf_full_path = *node_path;
1108 leaf_full_path.extend(key);
1109 Some((
1110 leaf_full_path,
1111 self.upper_subtrie
1112 .inner
1113 .values
1114 .remove(&leaf_full_path)
1115 .expect("leaf nodes have associated values entries"),
1116 ))
1117 } else {
1118 None
1119 };
1120
1121 let subtrie = self.subtrie_for_path_mut(node_path);
1122
1123 if let Some((leaf_full_path, value)) = leaf_value {
1124 subtrie.inner.values.insert(leaf_full_path, value);
1125 }
1126
1127 subtrie.nodes.insert(*node_path, node);
1128 }
1129
1130 if let Some(next_path) = next.filter(|n| !SparseSubtrieType::path_len_is_upper(n.len())) {
1131 self.upper_subtrie.inner.values.remove(&full_path);
1132
1133 let subtrie = self.subtrie_for_path_mut(&next_path);
1134
1135 if subtrie.nodes.is_empty() {
1136 subtrie.nodes.insert(subtrie.path, SparseNode::Empty);
1137 }
1138
1139 if let Err(e) = subtrie.update_leaf(full_path, value) {
1140 if let Some(lower) = self.lower_subtrie_for_path_mut(&full_path) {
1141 lower.inner.values.remove(&full_path);
1142 }
1143 return Err(e);
1144 }
1145 }
1146
1147 self.prefix_set.insert(full_path);
1148
1149 Ok(())
1150 }
1151
1152 pub fn remove_leaf(&mut self, full_path: &Nibbles) -> SparseTrieResult<()> {
1154 debug_assert_eq!(
1155 full_path.len(),
1156 B256::len_bytes() * 2,
1157 "remove_leaf full_path must be 64 nibbles (32 bytes), got {} nibbles",
1158 full_path.len()
1159 );
1160
1161 trace!(
1162 target: "trie::parallel_sparse",
1163 ?full_path,
1164 "Removing leaf",
1165 );
1166
1167 let leaf_path;
1168 let leaf_subtrie_type;
1169
1170 let mut branch_parent_path: Option<Nibbles> = None;
1171 let mut branch_parent_node: Option<SparseNode> = None;
1172
1173 let mut ext_grandparent_path: Option<Nibbles> = None;
1174 let mut ext_grandparent_node: Option<SparseNode> = None;
1175
1176 let mut curr_path = Nibbles::new();
1177 let mut curr_subtrie_type = SparseSubtrieType::Upper;
1178
1179 let mut paths_to_mark_dirty = Vec::new();
1180
1181 loop {
1182 let curr_subtrie = match curr_subtrie_type {
1183 SparseSubtrieType::Upper => &mut self.upper_subtrie,
1184 SparseSubtrieType::Lower(idx) => {
1185 self.lower_subtries[idx].as_revealed_mut().expect("lower subtrie is revealed")
1186 }
1187 };
1188 let curr_node = curr_subtrie.nodes.get_mut(&curr_path).unwrap();
1189
1190 match Self::find_next_to_leaf(&curr_path, curr_node, full_path) {
1191 FindNextToLeafOutcome::NotFound => return Ok(()),
1192 FindNextToLeafOutcome::BlindedNode(path) => {
1193 return Err(SparseTrieErrorKind::BlindedNode(path).into())
1194 }
1195 FindNextToLeafOutcome::Found => {
1196 leaf_path = curr_path;
1197 leaf_subtrie_type = curr_subtrie_type;
1198 break;
1199 }
1200 FindNextToLeafOutcome::ContinueFrom(next_path) => {
1201 match curr_node {
1202 SparseNode::Branch { .. } => {
1203 paths_to_mark_dirty
1204 .push((SparseSubtrieType::from_path(&curr_path), curr_path));
1205
1206 match (&branch_parent_path, &ext_grandparent_path) {
1207 (Some(branch), Some(ext)) if branch.len() > ext.len() => {
1208 ext_grandparent_path = None;
1209 ext_grandparent_node = None;
1210 }
1211 _ => (),
1212 };
1213 branch_parent_path = Some(curr_path);
1214 branch_parent_node = Some(curr_node.clone());
1215 }
1216 SparseNode::Extension { .. } => {
1217 paths_to_mark_dirty
1218 .push((SparseSubtrieType::from_path(&curr_path), curr_path));
1219 ext_grandparent_path = Some(curr_path);
1220 ext_grandparent_node = Some(curr_node.clone());
1221 }
1222 SparseNode::Empty | SparseNode::Leaf { .. } => {
1223 unreachable!(
1224 "find_next_to_leaf only continues to a branch or extension"
1225 )
1226 }
1227 }
1228
1229 curr_path = next_path;
1230
1231 let next_subtrie_type = SparseSubtrieType::from_path(&curr_path);
1232 if matches!(curr_subtrie_type, SparseSubtrieType::Upper) &&
1233 matches!(next_subtrie_type, SparseSubtrieType::Lower(_))
1234 {
1235 curr_subtrie_type = next_subtrie_type;
1236 }
1237 }
1238 };
1239 }
1240
1241 if let (Some(branch_path), Some(SparseNode::Branch { state_mask, blinded_mask, .. })) =
1242 (&branch_parent_path, &branch_parent_node)
1243 {
1244 let mut check_mask = *state_mask;
1245 let child_nibble = leaf_path.get_unchecked(branch_path.len());
1246 check_mask.unset_bit(child_nibble);
1247
1248 if check_mask.count_bits() == 1 {
1249 let remaining_nibble =
1250 check_mask.first_set_bit_index().expect("state mask is not empty");
1251
1252 if blinded_mask.is_bit_set(remaining_nibble) {
1253 let mut path = *branch_path;
1254 path.push_unchecked(remaining_nibble);
1255 return Err(SparseTrieErrorKind::BlindedNode(path).into());
1256 }
1257 }
1258 }
1259
1260 self.prefix_set.insert(*full_path);
1261 let leaf_subtrie = match leaf_subtrie_type {
1262 SparseSubtrieType::Upper => &mut self.upper_subtrie,
1263 SparseSubtrieType::Lower(idx) => {
1264 self.lower_subtries[idx].as_revealed_mut().expect("lower subtrie is revealed")
1265 }
1266 };
1267 leaf_subtrie.inner.values.remove(full_path);
1268 for (subtrie_type, path) in paths_to_mark_dirty {
1269 let node = match subtrie_type {
1270 SparseSubtrieType::Upper => self.upper_subtrie.nodes.get_mut(&path),
1271 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx]
1272 .as_revealed_mut()
1273 .expect("lower subtrie is revealed")
1274 .nodes
1275 .get_mut(&path),
1276 }
1277 .expect("node exists");
1278
1279 match node {
1280 SparseNode::Extension { state, .. } | SparseNode::Branch { state, .. } => {
1281 *state = SparseNodeState::Dirty
1282 }
1283 SparseNode::Empty | SparseNode::Leaf { .. } => {
1284 unreachable!(
1285 "only branch and extension nodes can be marked dirty when removing a leaf"
1286 )
1287 }
1288 }
1289 }
1290 self.remove_node(&leaf_path);
1291
1292 if leaf_path.is_empty() {
1293 self.upper_subtrie.nodes.insert(leaf_path, SparseNode::Empty);
1294 return Ok(());
1295 }
1296
1297 if let (
1298 Some(branch_path),
1299 &Some(SparseNode::Branch { mut state_mask, blinded_mask, ref blinded_hashes, .. }),
1300 ) = (&branch_parent_path, &branch_parent_node)
1301 {
1302 let child_nibble = leaf_path.get_unchecked(branch_path.len());
1303 state_mask.unset_bit(child_nibble);
1304
1305 let new_branch_node = if state_mask.count_bits() == 1 {
1306 let remaining_child_nibble =
1307 state_mask.first_set_bit_index().expect("state mask is not empty");
1308 let mut remaining_child_path = *branch_path;
1309 remaining_child_path.push_unchecked(remaining_child_nibble);
1310
1311 trace!(
1312 target: "trie::parallel_sparse",
1313 ?leaf_path,
1314 ?branch_path,
1315 ?remaining_child_path,
1316 "Branch node has only one child",
1317 );
1318
1319 if blinded_mask.is_bit_set(remaining_child_nibble) {
1320 return Err(SparseTrieErrorKind::BlindedNode(remaining_child_path).into());
1321 }
1322
1323 let remaining_child_node = self
1324 .subtrie_for_path_mut(&remaining_child_path)
1325 .nodes
1326 .get(&remaining_child_path)
1327 .unwrap();
1328
1329 let (new_branch_node, remove_child) = Self::branch_changes_on_leaf_removal(
1330 branch_path,
1331 &remaining_child_path,
1332 remaining_child_node,
1333 );
1334
1335 if remove_child {
1336 self.move_value_on_leaf_removal(
1337 branch_path,
1338 &new_branch_node,
1339 &remaining_child_path,
1340 );
1341 self.remove_node(&remaining_child_path);
1342 }
1343
1344 if let Some(updates) = self.updates.as_mut() {
1345 updates.updated_nodes.remove(branch_path);
1346 updates.removed_nodes.insert(*branch_path);
1347 }
1348
1349 new_branch_node
1350 } else {
1351 SparseNode::Branch {
1352 state_mask,
1353 blinded_mask,
1354 blinded_hashes: blinded_hashes.clone(),
1355 state: SparseNodeState::Dirty,
1356 }
1357 };
1358
1359 let branch_subtrie = self.subtrie_for_path_mut(branch_path);
1360 branch_subtrie.nodes.insert(*branch_path, new_branch_node.clone());
1361 branch_parent_node = Some(new_branch_node);
1362 };
1363
1364 if let (Some(ext_path), Some(SparseNode::Extension { key: shortkey, .. })) =
1365 (ext_grandparent_path, &ext_grandparent_node)
1366 {
1367 let ext_subtrie = self.subtrie_for_path_mut(&ext_path);
1368 let branch_path = branch_parent_path.as_ref().unwrap();
1369
1370 if let Some(new_ext_node) = Self::extension_changes_on_leaf_removal(
1371 &ext_path,
1372 shortkey,
1373 branch_path,
1374 branch_parent_node.as_ref().unwrap(),
1375 ) {
1376 ext_subtrie.nodes.insert(ext_path, new_ext_node.clone());
1377 self.move_value_on_leaf_removal(&ext_path, &new_ext_node, branch_path);
1378 self.remove_node(branch_path);
1379 }
1380 }
1381
1382 Ok(())
1383 }
1384
1385 fn finalize_pruned_roots(&mut self, mut effective_pruned_roots: Vec<Nibbles>) -> usize {
1386 if effective_pruned_roots.is_empty() {
1387 return 0;
1388 }
1389
1390 let nodes_converted = effective_pruned_roots.len();
1391
1392 effective_pruned_roots.sort_unstable_by(|path_a, path_b| {
1394 let subtrie_type_a = SparseSubtrieType::from_path(path_a);
1395 let subtrie_type_b = SparseSubtrieType::from_path(path_b);
1396 subtrie_type_a.cmp(&subtrie_type_b).then(path_a.cmp(path_b))
1397 });
1398
1399 let num_upper_roots = effective_pruned_roots
1401 .iter()
1402 .position(|p| !SparseSubtrieType::path_len_is_upper(p.len()))
1403 .unwrap_or(effective_pruned_roots.len());
1404
1405 let roots_upper = &effective_pruned_roots[..num_upper_roots];
1406 let roots_lower = &effective_pruned_roots[num_upper_roots..];
1407
1408 debug_assert!(
1409 {
1410 let mut all_roots: Vec<_> = effective_pruned_roots.clone();
1411 all_roots.sort_unstable();
1412 all_roots.windows(2).all(|w| !w[1].starts_with(&w[0]))
1413 },
1414 "prune roots must be prefix-free"
1415 );
1416
1417 if !roots_upper.is_empty() {
1420 for subtrie in &mut *self.lower_subtries {
1421 let should_clear = subtrie.as_revealed_ref().is_some_and(|s| {
1422 let search_idx = roots_upper.partition_point(|root| root <= &s.path);
1423 search_idx > 0 && s.path.starts_with(&roots_upper[search_idx - 1])
1424 });
1425 if should_clear {
1426 subtrie.clear();
1427 }
1428 }
1429 }
1430
1431 self.upper_subtrie.nodes.retain(|p, _| !is_strict_descendant_in(roots_upper, p));
1433 self.upper_subtrie.inner.values.retain(|p, _| {
1434 !starts_with_pruned_in(roots_upper, p) && !starts_with_pruned_in(roots_lower, p)
1435 });
1436
1437 for roots_group in roots_lower.chunk_by(|path_a, path_b| {
1439 SparseSubtrieType::from_path(path_a) == SparseSubtrieType::from_path(path_b)
1440 }) {
1441 let subtrie_idx = path_subtrie_index_unchecked(&roots_group[0]);
1442
1443 let should_clear = {
1445 let Some(subtrie) = self.lower_subtries[subtrie_idx].as_revealed_mut() else {
1446 continue;
1447 };
1448
1449 subtrie.nodes.retain(|p, _| !is_strict_descendant_in(roots_group, p));
1451 subtrie.inner.values.retain(|p, _| !starts_with_pruned_in(roots_group, p));
1452
1453 !subtrie.nodes.contains_key(&subtrie.path)
1456 };
1457
1458 if should_clear {
1459 self.lower_subtries[subtrie_idx].clear();
1460 }
1461 }
1462
1463 self.branch_node_masks.retain(|p, _| {
1465 if SparseSubtrieType::path_len_is_upper(p.len()) {
1466 !starts_with_pruned_in(roots_upper, p)
1467 } else {
1468 !starts_with_pruned_in(roots_lower, p) && !starts_with_pruned_in(roots_upper, p)
1469 }
1470 });
1471
1472 nodes_converted
1473 }
1474
1475 fn lower_subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
1479 match SparseSubtrieType::from_path(path) {
1480 SparseSubtrieType::Upper => None,
1481 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx].as_revealed_ref(),
1482 }
1483 }
1484
1485 fn lower_subtrie_for_path_mut(&mut self, path: &Nibbles) -> Option<&mut SparseSubtrie> {
1492 match SparseSubtrieType::from_path(path) {
1493 SparseSubtrieType::Upper => None,
1494 SparseSubtrieType::Lower(idx) => {
1495 self.lower_subtries[idx].reveal(path);
1496 Some(self.lower_subtries[idx].as_revealed_mut().expect("just revealed"))
1497 }
1498 }
1499 }
1500
1501 fn subtrie_for_path(&self, path: &Nibbles) -> Option<&SparseSubtrie> {
1506 if SparseSubtrieType::path_len_is_upper(path.len()) {
1507 Some(&self.upper_subtrie)
1508 } else {
1509 self.lower_subtrie_for_path(path)
1510 }
1511 }
1512
1513 fn subtrie_for_path_mut(&mut self, path: &Nibbles) -> &mut SparseSubtrie {
1520 if SparseSubtrieType::path_len_is_upper(path.len()) {
1523 &mut self.upper_subtrie
1524 } else {
1525 self.lower_subtrie_for_path_mut(path).unwrap()
1526 }
1527 }
1528
1529 fn subtrie_for_path_mut_untracked(&mut self, path: &Nibbles) -> Option<&mut SparseSubtrie> {
1532 if SparseSubtrieType::path_len_is_upper(path.len()) {
1533 Some(&mut self.upper_subtrie)
1534 } else {
1535 match SparseSubtrieType::from_path(path) {
1536 SparseSubtrieType::Upper => None,
1537 SparseSubtrieType::Lower(idx) => self.lower_subtries[idx].as_revealed_mut(),
1538 }
1539 }
1540 }
1541
1542 fn find_next_to_leaf(
1550 from_path: &Nibbles,
1551 from_node: &SparseNode,
1552 leaf_full_path: &Nibbles,
1553 ) -> FindNextToLeafOutcome {
1554 debug_assert!(leaf_full_path.len() >= from_path.len());
1555 debug_assert!(leaf_full_path.starts_with(from_path));
1556
1557 match from_node {
1558 SparseNode::Empty => FindNextToLeafOutcome::NotFound,
1561 SparseNode::Leaf { key, .. } => {
1562 let mut found_full_path = *from_path;
1563 found_full_path.extend(key);
1564
1565 if &found_full_path == leaf_full_path {
1566 return FindNextToLeafOutcome::Found
1567 }
1568 FindNextToLeafOutcome::NotFound
1569 }
1570 SparseNode::Extension { key, .. } => {
1571 if leaf_full_path.len() == from_path.len() {
1572 return FindNextToLeafOutcome::NotFound
1573 }
1574
1575 let mut child_path = *from_path;
1576 child_path.extend(key);
1577
1578 if !leaf_full_path.starts_with(&child_path) {
1579 return FindNextToLeafOutcome::NotFound
1580 }
1581 FindNextToLeafOutcome::ContinueFrom(child_path)
1582 }
1583 SparseNode::Branch { state_mask, blinded_mask, .. } => {
1584 if leaf_full_path.len() == from_path.len() {
1585 return FindNextToLeafOutcome::NotFound
1586 }
1587
1588 let nibble = leaf_full_path.get_unchecked(from_path.len());
1589 if !state_mask.is_bit_set(nibble) {
1590 return FindNextToLeafOutcome::NotFound
1591 }
1592
1593 let mut child_path = *from_path;
1594 child_path.push_unchecked(nibble);
1595
1596 if blinded_mask.is_bit_set(nibble) {
1597 return FindNextToLeafOutcome::BlindedNode(child_path);
1598 }
1599
1600 FindNextToLeafOutcome::ContinueFrom(child_path)
1601 }
1602 }
1603 }
1604
1605 fn move_value_on_leaf_removal(
1610 &mut self,
1611 parent_path: &Nibbles,
1612 new_parent_node: &SparseNode,
1613 prev_child_path: &Nibbles,
1614 ) {
1615 if SparseSubtrieType::from_path(parent_path).lower_index().is_some() {
1618 return;
1619 }
1620
1621 if let SparseNode::Leaf { key, .. } = new_parent_node {
1622 let Some(prev_child_subtrie) = self.lower_subtrie_for_path_mut(prev_child_path) else {
1623 return;
1624 };
1625
1626 let mut leaf_full_path = *parent_path;
1627 leaf_full_path.extend(key);
1628
1629 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");
1630 self.upper_subtrie.inner.values.insert(leaf_full_path, val);
1631 }
1632 }
1633
1634 fn remove_node(&mut self, path: &Nibbles) {
1646 let subtrie = self.subtrie_for_path_mut(path);
1647 let node = subtrie.nodes.remove(path);
1648
1649 let Some(idx) = SparseSubtrieType::from_path(path).lower_index() else {
1650 return;
1653 };
1654
1655 match node {
1656 Some(SparseNode::Leaf { .. }) => {
1657 if subtrie.nodes.is_empty() {
1660 self.lower_subtries[idx].clear();
1661 }
1662 }
1663 Some(SparseNode::Extension { key, .. }) => {
1664 if &subtrie.path == path {
1668 subtrie.path.extend(&key);
1669 }
1670 }
1671 _ => panic!("Expected to remove a leaf or extension, but removed {node:?}"),
1672 }
1673 }
1674
1675 fn branch_changes_on_leaf_removal(
1684 parent_path: &Nibbles,
1685 remaining_child_path: &Nibbles,
1686 remaining_child_node: &SparseNode,
1687 ) -> (SparseNode, bool) {
1688 debug_assert!(remaining_child_path.len() > parent_path.len());
1689 debug_assert!(remaining_child_path.starts_with(parent_path));
1690
1691 let remaining_child_nibble = remaining_child_path.get_unchecked(parent_path.len());
1692
1693 match remaining_child_node {
1696 SparseNode::Empty => {
1697 panic!("remaining child must have been revealed already")
1698 }
1699 SparseNode::Leaf { key, .. } => {
1703 let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1704 new_key.extend(key);
1705 (SparseNode::new_leaf(new_key), true)
1706 }
1707 SparseNode::Extension { key, .. } => {
1711 let mut new_key = Nibbles::from_nibbles_unchecked([remaining_child_nibble]);
1712 new_key.extend(key);
1713 (SparseNode::new_ext(new_key), true)
1714 }
1715 SparseNode::Branch { .. } => (
1718 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([remaining_child_nibble])),
1719 false,
1720 ),
1721 }
1722 }
1723
1724 fn extension_changes_on_leaf_removal(
1733 parent_path: &Nibbles,
1734 parent_key: &Nibbles,
1735 child_path: &Nibbles,
1736 child: &SparseNode,
1737 ) -> Option<SparseNode> {
1738 debug_assert!(child_path.len() > parent_path.len());
1739 debug_assert!(child_path.starts_with(parent_path));
1740
1741 match child {
1744 SparseNode::Empty => {
1745 panic!("child must be revealed")
1746 }
1747 SparseNode::Leaf { key, .. } => {
1753 let mut new_key = *parent_key;
1754 new_key.extend(key);
1755 Some(SparseNode::new_leaf(new_key))
1756 }
1757 SparseNode::Extension { key, .. } => {
1760 let mut new_key = *parent_key;
1761 new_key.extend(key);
1762 Some(SparseNode::new_ext(new_key))
1763 }
1764 SparseNode::Branch { .. } => None,
1766 }
1767 }
1768
1769 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
1772 fn apply_subtrie_update_actions(
1773 &mut self,
1774 update_actions: impl Iterator<Item = SparseTrieUpdatesAction>,
1775 ) {
1776 if let Some(updates) = self.updates.as_mut() {
1777 let additional = update_actions.size_hint().0;
1778 updates.updated_nodes.reserve(additional);
1779 updates.removed_nodes.reserve(additional);
1780 for action in update_actions {
1781 match action {
1782 SparseTrieUpdatesAction::InsertRemoved(path) => {
1783 updates.updated_nodes.remove(&path);
1784 updates.removed_nodes.insert(path);
1785 }
1786 SparseTrieUpdatesAction::RemoveUpdated(path) => {
1787 updates.updated_nodes.remove(&path);
1788 }
1789 SparseTrieUpdatesAction::InsertUpdated(path, branch_node) => {
1790 updates.updated_nodes.insert(path, branch_node);
1791 updates.removed_nodes.remove(&path);
1792 }
1793 }
1794 }
1795 };
1796 }
1797
1798 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, ret)]
1800 fn update_upper_subtrie_hashes(&mut self, prefix_set: &mut PrefixSet) -> RlpNode {
1801 trace!(target: "trie::parallel_sparse", "Updating upper subtrie hashes");
1802
1803 debug_assert!(self.upper_subtrie.inner.buffers.path_stack.is_empty());
1804 self.upper_subtrie.inner.buffers.path_stack.push(RlpNodePathStackItem {
1805 path: Nibbles::default(), is_in_prefix_set: None,
1807 });
1808
1809 #[cfg(feature = "metrics")]
1810 let start = Instant::now();
1811
1812 let mut update_actions_buf =
1813 self.updates_enabled().then(|| self.update_actions_buffers.pop().unwrap_or_default());
1814
1815 while let Some(stack_item) = self.upper_subtrie.inner.buffers.path_stack.pop() {
1816 let path = stack_item.path;
1817 let node = if path.len() < UPPER_TRIE_MAX_DEPTH {
1818 self.upper_subtrie.nodes.get_mut(&path).expect("upper subtrie node must exist")
1819 } else {
1820 let index = path_subtrie_index_unchecked(&path);
1821 let node = self.lower_subtries[index]
1822 .as_revealed_mut()
1823 .expect("lower subtrie must exist")
1824 .nodes
1825 .get_mut(&path)
1826 .expect("lower subtrie node must exist");
1827 debug_assert!(
1830 node.cached_rlp_node().is_some(),
1831 "Lower subtrie root node {node:?} at path {path:?} has no cached RLP node"
1832 );
1833 node
1834 };
1835
1836 self.upper_subtrie.inner.rlp_node(
1838 prefix_set,
1839 &mut update_actions_buf,
1840 stack_item,
1841 node,
1842 &self.branch_node_masks,
1843 );
1844 }
1845
1846 if let Some(mut update_actions_buf) = update_actions_buf {
1849 self.apply_subtrie_update_actions(
1850 #[expect(clippy::iter_with_drain)]
1851 update_actions_buf.drain(..),
1852 );
1853 self.update_actions_buffers.push(update_actions_buf);
1854 }
1855
1856 #[cfg(feature = "metrics")]
1857 self.metrics.subtrie_upper_hash_latency.record(start.elapsed());
1858
1859 debug_assert_eq!(self.upper_subtrie.inner.buffers.rlp_node_stack.len(), 1);
1860 self.upper_subtrie.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
1861 }
1862
1863 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(prefix_set_len = prefix_set.len()))]
1877 fn take_changed_lower_subtries(
1878 &mut self,
1879 prefix_set: &mut PrefixSet,
1880 ) -> (Vec<ChangedSubtrie>, PrefixSetMut) {
1881 if prefix_set.is_empty() {
1884 return Default::default();
1885 }
1886
1887 let prefix_set_clone = prefix_set.clone();
1889 let mut prefix_set_iter = prefix_set_clone.into_iter().copied().peekable();
1890 let mut changed_subtries = Vec::new();
1891 let mut unchanged_prefix_set = PrefixSetMut::default();
1892 let updates_enabled = self.updates_enabled();
1893
1894 for (index, subtrie) in self.lower_subtries.iter_mut().enumerate() {
1895 if let Some(subtrie) = subtrie.take_revealed_if(|subtrie| {
1896 prefix_set.contains(&subtrie.path) ||
1897 subtrie
1898 .nodes
1899 .get(&subtrie.path)
1900 .is_some_and(|n| n.cached_rlp_node().is_none())
1901 }) {
1902 let prefix_set = if prefix_set.all() {
1903 unchanged_prefix_set = PrefixSetMut::all();
1904 PrefixSetMut::all()
1905 } else {
1906 let mut new_prefix_set = Vec::new();
1911 while let Some(key) = prefix_set_iter.peek() {
1912 if key.starts_with(&subtrie.path) {
1913 new_prefix_set.push(prefix_set_iter.next().unwrap());
1915 } else if new_prefix_set.is_empty() && key < &subtrie.path {
1916 unchanged_prefix_set.insert(prefix_set_iter.next().unwrap());
1920 } else {
1921 break
1925 }
1926 }
1927 PrefixSetMut::from(new_prefix_set)
1928 }
1929 .freeze();
1930
1931 match subtrie.nodes.get(&subtrie.path) {
1934 Some(SparseNode::Extension { key, .. } | SparseNode::Leaf { key, .. }) => {
1935 unchanged_prefix_set.insert(subtrie.path.join(key));
1936 }
1937 Some(SparseNode::Branch { .. }) => {
1938 unchanged_prefix_set.insert(subtrie.path);
1939 }
1940 _ => {}
1941 }
1942
1943 let update_actions_buf =
1944 updates_enabled.then(|| self.update_actions_buffers.pop().unwrap_or_default());
1945
1946 changed_subtries.push(ChangedSubtrie {
1947 index,
1948 subtrie,
1949 prefix_set,
1950 update_actions_buf,
1951 });
1952 }
1953 }
1954
1955 unchanged_prefix_set.extend_keys(prefix_set_iter);
1957
1958 (changed_subtries, unchanged_prefix_set)
1959 }
1960
1961 #[cfg(test)]
1963 fn all_nodes(&self) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
1964 let mut nodes = vec![];
1965 for subtrie in self.lower_subtries.iter().filter_map(LowerSparseSubtrie::as_revealed_ref) {
1966 nodes.extend(subtrie.nodes.iter())
1967 }
1968 nodes.extend(self.upper_subtrie.nodes.iter());
1969 nodes
1970 }
1971
1972 fn reveal_upper_node(
1989 &mut self,
1990 path: Nibbles,
1991 node: &TrieNodeV2,
1992 masks: Option<BranchNodeMasks>,
1993 ) -> SparseTrieResult<()> {
1994 if !self.is_path_reachable_from_upper(&path) {
1997 return Ok(())
1998 }
1999
2000 if !self.upper_subtrie.reveal_node(path, node, masks, None)? {
2002 if let TrieNodeV2::Branch(branch) = node {
2003 if branch.key.is_empty() {
2004 return Ok(());
2005 }
2006
2007 if SparseSubtrieType::path_len_is_upper(path.len() + branch.key.len()) {
2010 return Ok(())
2011 }
2012 } else {
2013 return Ok(());
2014 }
2015 }
2016
2017 match node {
2022 TrieNodeV2::Branch(branch) => {
2023 let mut branch_path = path;
2024 branch_path.extend(&branch.key);
2025
2026 if !SparseSubtrieType::path_len_is_upper(branch_path.len()) {
2029 self.lower_subtrie_for_path_mut(&branch_path)
2030 .expect("branch_path must have a lower subtrie")
2031 .reveal_branch(
2032 branch_path,
2033 branch.state_mask,
2034 &branch.stack,
2035 masks,
2036 branch.branch_rlp_node.clone(),
2037 )?
2038 } else if !SparseSubtrieType::path_len_is_upper(branch_path.len() + 1) {
2039 for (stack_ptr, idx) in branch.state_mask.iter().enumerate() {
2044 let mut child_path = branch_path;
2045 child_path.push_unchecked(idx);
2046 let child = &branch.stack[stack_ptr];
2047
2048 if !child.is_hash() {
2051 self.lower_subtrie_for_path_mut(&child_path)
2052 .expect("child_path must have a lower subtrie")
2053 .reveal_node(
2054 child_path,
2055 &TrieNodeV2::decode(&mut branch.stack[stack_ptr].as_ref())?,
2056 None,
2057 None,
2058 )?;
2059 }
2060 }
2061 }
2062 }
2063 TrieNodeV2::Extension(ext) => {
2064 let mut child_path = path;
2065 child_path.extend(&ext.key);
2066 if let Some(subtrie) = self.lower_subtrie_for_path_mut(&child_path) {
2067 subtrie.reveal_node(
2068 child_path,
2069 &TrieNodeV2::decode(&mut ext.child.as_ref())?,
2070 None,
2071 None,
2072 )?;
2073 }
2074 }
2075 TrieNodeV2::EmptyRoot | TrieNodeV2::Leaf(_) => (),
2076 }
2077
2078 Ok(())
2079 }
2080
2081 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all)]
2084 fn insert_changed_subtries(
2085 &mut self,
2086 changed_subtries: impl IntoIterator<Item = ChangedSubtrie>,
2087 ) {
2088 for ChangedSubtrie { index, subtrie, update_actions_buf, .. } in changed_subtries {
2089 if let Some(mut update_actions_buf) = update_actions_buf {
2090 self.apply_subtrie_update_actions(
2091 #[expect(clippy::iter_with_drain)]
2092 update_actions_buf.drain(..),
2093 );
2094 self.update_actions_buffers.push(update_actions_buf);
2095 }
2096
2097 self.lower_subtries[index] = LowerSparseSubtrie::Revealed(subtrie);
2098 }
2099 }
2100
2101 pub fn memory_size(&self) -> usize {
2113 let mut size = core::mem::size_of::<Self>();
2114
2115 size += self.upper_subtrie.memory_size();
2117
2118 for subtrie in self.lower_subtries.iter() {
2120 size += subtrie.memory_size();
2121 }
2122
2123 size += self.prefix_set.len() * core::mem::size_of::<Nibbles>();
2125
2126 size += self.branch_node_masks.len() *
2128 (core::mem::size_of::<Nibbles>() + core::mem::size_of::<BranchNodeMasks>());
2129
2130 if let Some(updates) = &self.updates {
2132 size += updates.updated_nodes.len() *
2133 (core::mem::size_of::<Nibbles>() + core::mem::size_of::<BranchNodeCompact>());
2134 size += updates.removed_nodes.len() * core::mem::size_of::<Nibbles>();
2135 }
2136
2137 for buf in &self.update_actions_buffers {
2139 size += buf.capacity() * core::mem::size_of::<SparseTrieUpdatesAction>();
2140 }
2141
2142 size
2143 }
2144
2145 fn is_path_reachable_from_upper(&self, path: &Nibbles) -> bool {
2147 let mut current = Nibbles::default();
2148 while current.len() < path.len() {
2149 let Some(node) = self.upper_subtrie.nodes.get(¤t) else { return false };
2150 match node {
2151 SparseNode::Branch { state_mask, .. } => {
2152 if !state_mask.is_bit_set(path.get_unchecked(current.len())) {
2153 return false
2154 }
2155
2156 current.push_unchecked(path.get_unchecked(current.len()));
2157 }
2158 SparseNode::Extension { key, .. } => {
2159 if *key != path.slice(current.len()..current.len() + key.len()) {
2160 return false
2161 }
2162 current.extend(key);
2163 }
2164 SparseNode::Empty | SparseNode::Leaf { .. } => return false,
2165 }
2166 }
2167 true
2168 }
2169
2170 fn is_boundary_leaf_reachable(
2176 upper_nodes: &HashMap<Nibbles, SparseNode>,
2177 path: &Nibbles,
2178 node: &TrieNodeV2,
2179 ) -> bool {
2180 debug_assert_eq!(path.len(), UPPER_TRIE_MAX_DEPTH);
2181
2182 if !matches!(node, TrieNodeV2::Leaf(_)) {
2183 return true
2184 }
2185
2186 let parent_path = path.slice(..path.len() - 1);
2187 let leaf_nibble = path.get_unchecked(path.len() - 1);
2188
2189 match upper_nodes.get(&parent_path) {
2190 Some(SparseNode::Branch { state_mask, .. }) => state_mask.is_bit_set(leaf_nibble),
2191 _ => false,
2192 }
2193 }
2194
2195 fn reachable_subtries(&self) -> SubtriesBitmap {
2198 let mut reachable = SubtriesBitmap::default();
2199
2200 let mut stack = Vec::new();
2201 stack.push(Nibbles::default());
2202
2203 while let Some(current) = stack.pop() {
2204 let Some(node) = self.upper_subtrie.nodes.get(¤t) else { continue };
2205 match node {
2206 SparseNode::Branch { state_mask, .. } => {
2207 for idx in state_mask.iter() {
2208 let mut next = current;
2209 next.push_unchecked(idx);
2210 if next.len() >= UPPER_TRIE_MAX_DEPTH {
2211 reachable.set(path_subtrie_index_unchecked(&next));
2212 } else {
2213 stack.push(next);
2214 }
2215 }
2216 }
2217 SparseNode::Extension { key, .. } => {
2218 let mut next = current;
2219 next.extend(key);
2220 if next.len() >= UPPER_TRIE_MAX_DEPTH {
2221 reachable.set(path_subtrie_index_unchecked(&next));
2222 } else {
2223 stack.push(next);
2224 }
2225 }
2226 SparseNode::Empty | SparseNode::Leaf { .. } => {}
2227 };
2228 }
2229
2230 reachable
2231 }
2232}
2233
2234#[derive(Clone, Default, PartialEq, Eq, Debug)]
2236struct SubtriesBitmap(U256);
2237
2238impl SubtriesBitmap {
2239 #[inline]
2241 fn set(&mut self, idx: usize) {
2242 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2243 self.0.set_bit(idx, true);
2244 }
2245
2246 #[inline]
2248 fn get(&self, idx: usize) -> bool {
2249 debug_assert!(idx < NUM_LOWER_SUBTRIES);
2250 self.0.bit(idx)
2251 }
2252}
2253
2254#[derive(Clone, PartialEq, Eq, Debug, Default)]
2257pub struct SparseSubtrie {
2258 pub(crate) path: Nibbles,
2266 nodes: HashMap<Nibbles, SparseNode>,
2268 inner: SparseSubtrieInner,
2270}
2271
2272enum FindNextToLeafOutcome {
2275 Found,
2277 ContinueFrom(Nibbles),
2279 NotFound,
2282 BlindedNode(Nibbles),
2285}
2286
2287impl SparseSubtrie {
2288 pub(crate) fn new(path: Nibbles) -> Self {
2290 Self { path, ..Default::default() }
2291 }
2292
2293 pub(crate) fn is_empty(&self) -> bool {
2295 self.nodes.is_empty()
2296 }
2297
2298 fn is_child_same_level(current_path: &Nibbles, child_path: &Nibbles) -> bool {
2300 let current_level = core::mem::discriminant(&SparseSubtrieType::from_path(current_path));
2301 let child_level = core::mem::discriminant(&SparseSubtrieType::from_path(child_path));
2302 current_level == child_level
2303 }
2304
2305 fn is_leaf_reachable_from_parent(&self, path: &Nibbles) -> bool {
2314 if path.is_empty() {
2315 return true
2316 }
2317
2318 let parent_path = path.slice(..path.len() - 1);
2319 let leaf_nibble = path.get_unchecked(path.len() - 1);
2320
2321 match self.nodes.get(&parent_path) {
2322 Some(SparseNode::Branch { state_mask, .. }) => state_mask.is_bit_set(leaf_nibble),
2323 _ => false,
2324 }
2325 }
2326
2327 pub fn update_leaf(&mut self, full_path: Nibbles, value: Vec<u8>) -> SparseTrieResult<()> {
2338 debug_assert!(full_path.starts_with(&self.path));
2339
2340 if let Entry::Occupied(mut e) = self.inner.values.entry(full_path) {
2342 e.insert(value);
2343 return Ok(())
2344 }
2345
2346 let mut current = Some(self.path);
2348
2349 while let Some(current_path) = current.as_mut() {
2350 match self.update_next_node(current_path, &full_path)? {
2351 LeafUpdateStep::Continue => {}
2352 LeafUpdateStep::NodeNotFound | LeafUpdateStep::Complete { .. } => break,
2353 }
2354 }
2355
2356 self.inner.values.insert(full_path, value);
2358
2359 Ok(())
2360 }
2361
2362 fn update_next_node(
2369 &mut self,
2370 current: &mut Nibbles,
2371 path: &Nibbles,
2372 ) -> SparseTrieResult<LeafUpdateStep> {
2373 debug_assert!(path.starts_with(&self.path));
2374 debug_assert!(current.starts_with(&self.path));
2375 debug_assert!(path.starts_with(current));
2376 let Some(node) = self.nodes.get_mut(current) else {
2377 return Ok(LeafUpdateStep::NodeNotFound);
2378 };
2379
2380 match node {
2381 SparseNode::Empty => {
2382 let path = path.slice(self.path.len()..);
2385 *node = SparseNode::new_leaf(path);
2386 Ok(LeafUpdateStep::complete_with_insertions(vec![*current]))
2387 }
2388 SparseNode::Leaf { key: current_key, .. } => {
2389 current.extend(current_key);
2390
2391 debug_assert!(current != path, "we already checked leaf presence in the beginning");
2393
2394 let common = current.common_prefix_length(path);
2396
2397 let new_ext_key = current.slice(current.len() - current_key.len()..common);
2399 *node = SparseNode::new_ext(new_ext_key);
2400
2401 self.nodes.reserve(3);
2403 let branch_path = current.slice(..common);
2404 let new_leaf_path = path.slice(..=common);
2405 let existing_leaf_path = current.slice(..=common);
2406
2407 self.nodes.insert(
2408 branch_path,
2409 SparseNode::new_split_branch(
2410 current.get_unchecked(common),
2411 path.get_unchecked(common),
2412 ),
2413 );
2414 self.nodes.insert(new_leaf_path, SparseNode::new_leaf(path.slice(common + 1..)));
2415 self.nodes
2416 .insert(existing_leaf_path, SparseNode::new_leaf(current.slice(common + 1..)));
2417
2418 Ok(LeafUpdateStep::complete_with_insertions(vec![
2419 branch_path,
2420 new_leaf_path,
2421 existing_leaf_path,
2422 ]))
2423 }
2424 SparseNode::Extension { key, .. } => {
2425 current.extend(key);
2426
2427 if !path.starts_with(current) {
2428 let common = current.common_prefix_length(path);
2430 *key = current.slice(current.len() - key.len()..common);
2431
2432 self.nodes.reserve(3);
2435 let branch_path = current.slice(..common);
2436 let new_leaf_path = path.slice(..=common);
2437 let branch = SparseNode::new_split_branch(
2438 current.get_unchecked(common),
2439 path.get_unchecked(common),
2440 );
2441
2442 self.nodes.insert(branch_path, branch);
2443
2444 let new_leaf = SparseNode::new_leaf(path.slice(common + 1..));
2446 self.nodes.insert(new_leaf_path, new_leaf);
2447
2448 let mut inserted_nodes = vec![branch_path, new_leaf_path];
2449
2450 let key = current.slice(common + 1..);
2452 if !key.is_empty() {
2453 let ext_path = current.slice(..=common);
2454 self.nodes.insert(ext_path, SparseNode::new_ext(key));
2455 inserted_nodes.push(ext_path);
2456 }
2457
2458 return Ok(LeafUpdateStep::complete_with_insertions(inserted_nodes))
2459 }
2460
2461 Ok(LeafUpdateStep::Continue)
2462 }
2463 SparseNode::Branch { state_mask, blinded_mask, .. } => {
2464 let nibble = path.get_unchecked(current.len());
2465 current.push_unchecked(nibble);
2466
2467 if !state_mask.is_bit_set(nibble) {
2468 state_mask.set_bit(nibble);
2469 let new_leaf = SparseNode::new_leaf(path.slice(current.len()..));
2470 self.nodes.insert(*current, new_leaf);
2471 return Ok(LeafUpdateStep::complete_with_insertions(vec![*current]))
2472 }
2473
2474 if blinded_mask.is_bit_set(nibble) {
2475 return Err(SparseTrieErrorKind::BlindedNode(*current).into());
2476 }
2477
2478 Ok(LeafUpdateStep::Continue)
2480 }
2481 }
2482 }
2483
2484 fn reveal_branch(
2486 &mut self,
2487 path: Nibbles,
2488 state_mask: TrieMask,
2489 children: &[RlpNode],
2490 masks: Option<BranchNodeMasks>,
2491 rlp_node: Option<RlpNode>,
2492 ) -> SparseTrieResult<()> {
2493 match self.nodes.entry(path) {
2494 Entry::Occupied(_) => {
2495 return Ok(());
2497 }
2498 Entry::Vacant(entry) => {
2499 let state =
2500 match rlp_node.as_ref() {
2501 Some(rlp_node) => SparseNodeState::Cached {
2502 rlp_node: rlp_node.clone(),
2503 store_in_db_trie: Some(masks.is_some_and(|m| {
2504 !m.hash_mask.is_empty() || !m.tree_mask.is_empty()
2505 })),
2506 },
2507 None => SparseNodeState::Dirty,
2508 };
2509
2510 let mut blinded_mask = TrieMask::default();
2511 let mut blinded_hashes = Box::new([B256::ZERO; 16]);
2512
2513 for (stack_ptr, idx) in state_mask.iter().enumerate() {
2514 let mut child_path = path;
2515 child_path.push_unchecked(idx);
2516 let child = &children[stack_ptr];
2517
2518 if let Some(hash) = child.as_hash() {
2519 blinded_mask.set_bit(idx);
2520 blinded_hashes[idx as usize] = hash;
2521 }
2522 }
2523
2524 entry.insert(SparseNode::Branch {
2525 state_mask,
2526 state,
2527 blinded_mask,
2528 blinded_hashes,
2529 });
2530 }
2531 }
2532
2533 for (stack_ptr, idx) in state_mask.iter().enumerate() {
2536 let mut child_path = path;
2537 child_path.push_unchecked(idx);
2538 let child = &children[stack_ptr];
2539 if !child.is_hash() && Self::is_child_same_level(&path, &child_path) {
2540 self.reveal_node(
2543 child_path,
2544 &TrieNodeV2::decode(&mut child.as_ref())?,
2545 None,
2546 None,
2547 )?;
2548 }
2549 }
2550
2551 Ok(())
2552 }
2553
2554 fn reveal_node(
2559 &mut self,
2560 path: Nibbles,
2561 node: &TrieNodeV2,
2562 masks: Option<BranchNodeMasks>,
2563 hash_from_upper: Option<B256>,
2564 ) -> SparseTrieResult<bool> {
2565 debug_assert!(path.starts_with(&self.path));
2566
2567 if self.nodes.contains_key(&path) {
2569 return Ok(false);
2570 }
2571
2572 let hash = if let Some(hash) = hash_from_upper {
2575 Some(hash)
2576 } else if path.len() != UPPER_TRIE_MAX_DEPTH && !path.is_empty() {
2577 let Some(SparseNode::Branch { state_mask, blinded_mask, blinded_hashes, .. }) =
2578 self.nodes.get_mut(&path.slice(0..path.len() - 1))
2579 else {
2580 return Ok(false);
2581 };
2582 let nibble = path.last().unwrap();
2583 if !state_mask.is_bit_set(nibble) {
2584 return Ok(false);
2585 }
2586
2587 blinded_mask.is_bit_set(nibble).then(|| {
2588 blinded_mask.unset_bit(nibble);
2589 blinded_hashes[nibble as usize]
2590 })
2591 } else {
2592 None
2593 };
2594
2595 trace!(
2596 target: "trie::parallel_sparse",
2597 ?path,
2598 ?node,
2599 ?masks,
2600 "Revealing node",
2601 );
2602
2603 match node {
2604 TrieNodeV2::EmptyRoot => {
2605 debug_assert!(path.is_empty());
2607 debug_assert!(self.path.is_empty());
2608 self.nodes.insert(path, SparseNode::Empty);
2609 }
2610 TrieNodeV2::Branch(branch) => {
2611 if branch.key.is_empty() {
2612 self.reveal_branch(
2613 path,
2614 branch.state_mask,
2615 &branch.stack,
2616 masks,
2617 hash.as_ref().map(RlpNode::word_rlp),
2618 )?;
2619 return Ok(true);
2620 }
2621
2622 self.nodes.insert(
2623 path,
2624 SparseNode::Extension {
2625 key: branch.key,
2626 state: hash
2627 .as_ref()
2628 .map(|hash| SparseNodeState::Cached {
2629 rlp_node: RlpNode::word_rlp(hash),
2630 store_in_db_trie: Some(masks.is_some_and(|m| {
2634 !m.hash_mask.is_empty() || !m.tree_mask.is_empty()
2635 })),
2636 })
2637 .unwrap_or(SparseNodeState::Dirty),
2638 },
2639 );
2640
2641 let mut branch_path = path;
2642 branch_path.extend(&branch.key);
2643
2644 if !Self::is_child_same_level(&path, &branch_path) {
2646 return Ok(true);
2647 }
2648
2649 self.reveal_branch(
2651 branch_path,
2652 branch.state_mask,
2653 &branch.stack,
2654 masks,
2655 branch.branch_rlp_node.clone(),
2656 )?;
2657 }
2658 TrieNodeV2::Extension(_) => unreachable!(),
2659 TrieNodeV2::Leaf(leaf) => {
2660 if path.len() != UPPER_TRIE_MAX_DEPTH && !self.is_leaf_reachable_from_parent(&path)
2665 {
2666 trace!(
2667 target: "trie::parallel_sparse",
2668 ?path,
2669 "Leaf not reachable from parent branch, skipping",
2670 );
2671 return Ok(false)
2672 }
2673
2674 let mut full_key = path;
2675 full_key.extend(&leaf.key);
2676
2677 match self.inner.values.entry(full_key) {
2678 Entry::Occupied(_) => {
2679 trace!(
2680 target: "trie::parallel_sparse",
2681 ?path,
2682 ?full_key,
2683 "Leaf full key value already present, skipping",
2684 );
2685 return Ok(false)
2686 }
2687 Entry::Vacant(entry) => {
2688 entry.insert(leaf.value.clone());
2689 }
2690 }
2691
2692 self.nodes.insert(
2693 path,
2694 SparseNode::Leaf {
2695 key: leaf.key,
2696 state: hash
2697 .as_ref()
2698 .map(|hash| SparseNodeState::Cached {
2699 rlp_node: RlpNode::word_rlp(hash),
2700 store_in_db_trie: Some(false),
2701 })
2702 .unwrap_or(SparseNodeState::Dirty),
2703 },
2704 );
2705 }
2706 }
2707
2708 Ok(true)
2709 }
2710
2711 #[instrument(level = "trace", target = "trie::parallel_sparse", skip_all, fields(root = ?self.path), ret)]
2733 fn update_hashes(
2734 &mut self,
2735 prefix_set: &mut PrefixSet,
2736 update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
2737 branch_node_masks: &BranchNodeMasksMap,
2738 ) -> RlpNode {
2739 trace!(target: "trie::parallel_sparse", "Updating subtrie hashes");
2740
2741 debug_assert!(prefix_set.iter().all(|path| path.starts_with(&self.path)));
2742
2743 debug_assert!(self.inner.buffers.path_stack.is_empty());
2744 self.inner
2745 .buffers
2746 .path_stack
2747 .push(RlpNodePathStackItem { path: self.path, is_in_prefix_set: None });
2748
2749 while let Some(stack_item) = self.inner.buffers.path_stack.pop() {
2750 let path = stack_item.path;
2751 let node = self
2752 .nodes
2753 .get_mut(&path)
2754 .unwrap_or_else(|| panic!("node at path {path:?} does not exist"));
2755
2756 self.inner.rlp_node(prefix_set, update_actions, stack_item, node, branch_node_masks);
2757 }
2758
2759 debug_assert_eq!(self.inner.buffers.rlp_node_stack.len(), 1);
2760 self.inner.buffers.rlp_node_stack.pop().unwrap().rlp_node
2761 }
2762
2763 fn wipe(&mut self) {
2766 self.nodes.clear();
2767 self.nodes.insert(Nibbles::default(), SparseNode::Empty);
2768 self.inner.clear();
2769 }
2770
2771 pub(crate) fn clear(&mut self) {
2773 self.nodes.clear();
2774 self.inner.clear();
2775 }
2776
2777 pub(crate) fn shrink_nodes_to(&mut self, size: usize) {
2779 self.nodes.shrink_to(size);
2780 }
2781
2782 pub(crate) fn shrink_values_to(&mut self, size: usize) {
2784 self.inner.values.shrink_to(size);
2785 }
2786
2787 pub(crate) fn memory_size(&self) -> usize {
2789 let mut size = core::mem::size_of::<Self>();
2790
2791 for (path, node) in &self.nodes {
2793 size += core::mem::size_of::<Nibbles>();
2794 size += path.len(); size += node.memory_size();
2796 }
2797
2798 for (path, value) in &self.inner.values {
2800 size += core::mem::size_of::<Nibbles>();
2801 size += path.len(); size += core::mem::size_of::<Vec<u8>>() + value.capacity();
2803 }
2804
2805 size += self.inner.buffers.memory_size();
2807
2808 size
2809 }
2810}
2811
2812#[derive(Clone, PartialEq, Eq, Debug, Default)]
2815struct SparseSubtrieInner {
2816 values: HashMap<Nibbles, Vec<u8>>,
2819 buffers: SparseSubtrieBuffers,
2821}
2822
2823impl SparseSubtrieInner {
2824 fn rlp_node(
2854 &mut self,
2855 prefix_set: &mut PrefixSet,
2856 update_actions: &mut Option<Vec<SparseTrieUpdatesAction>>,
2857 mut stack_item: RlpNodePathStackItem,
2858 node: &mut SparseNode,
2859 branch_node_masks: &BranchNodeMasksMap,
2860 ) {
2861 let path = stack_item.path;
2862 trace!(
2863 target: "trie::parallel_sparse",
2864 ?path,
2865 ?node,
2866 "Calculating node RLP"
2867 );
2868
2869 let mut prefix_set_contains = |path: &Nibbles| {
2873 *stack_item.is_in_prefix_set.get_or_insert_with(|| prefix_set.contains(path))
2874 };
2875
2876 let (rlp_node, node_type) = match node {
2877 SparseNode::Empty => (RlpNode::word_rlp(&EMPTY_ROOT_HASH), SparseNodeType::Empty),
2878 SparseNode::Leaf { key, state } => {
2879 let mut path = path;
2880 path.extend(key);
2881 let value = self.values.get(&path);
2882
2883 let cached_rlp_node = state.cached_rlp_node();
2888 let use_cached =
2889 cached_rlp_node.is_some() && (!prefix_set_contains(&path) || value.is_none());
2890
2891 if let Some(rlp_node) = use_cached.then(|| cached_rlp_node.unwrap()) {
2892 (rlp_node.clone(), SparseNodeType::Leaf)
2894 } else {
2895 let value = value.expect("leaf value must exist in subtrie");
2897 self.buffers.rlp_buf.clear();
2898 let rlp_node = LeafNodeRef { key, value }.rlp(&mut self.buffers.rlp_buf);
2899 *state = SparseNodeState::Cached {
2900 rlp_node: rlp_node.clone(),
2901 store_in_db_trie: Some(false),
2902 };
2903 trace!(
2904 target: "trie::parallel_sparse",
2905 ?path,
2906 ?key,
2907 value = %alloy_primitives::hex::encode(value),
2908 ?rlp_node,
2909 "Calculated leaf RLP node",
2910 );
2911 (rlp_node, SparseNodeType::Leaf)
2912 }
2913 }
2914 SparseNode::Extension { key, state } => {
2915 let mut child_path = path;
2916 child_path.extend(key);
2917 if let Some((rlp_node, store_in_db_trie)) = state
2918 .cached_rlp_node()
2919 .zip(state.store_in_db_trie())
2920 .filter(|_| !prefix_set_contains(&path))
2921 {
2922 (
2925 rlp_node.clone(),
2926 SparseNodeType::Extension { store_in_db_trie: Some(store_in_db_trie) },
2927 )
2928 } else if self.buffers.rlp_node_stack.last().is_some_and(|e| e.path == child_path) {
2929 let RlpNodeStackItem { path: _, rlp_node: child, node_type: child_node_type } =
2932 self.buffers.rlp_node_stack.pop().unwrap();
2933 self.buffers.rlp_buf.clear();
2934 let rlp_node =
2935 ExtensionNodeRef::new(key, &child).rlp(&mut self.buffers.rlp_buf);
2936
2937 let store_in_db_trie_value = child_node_type.store_in_db_trie();
2938
2939 trace!(
2940 target: "trie::parallel_sparse",
2941 ?path,
2942 ?child_path,
2943 ?child_node_type,
2944 "Extension node"
2945 );
2946
2947 *state = SparseNodeState::Cached {
2948 rlp_node: rlp_node.clone(),
2949 store_in_db_trie: store_in_db_trie_value,
2950 };
2951
2952 (
2953 rlp_node,
2954 SparseNodeType::Extension {
2955 store_in_db_trie: store_in_db_trie_value,
2958 },
2959 )
2960 } else {
2961 self.buffers.path_stack.extend([
2964 RlpNodePathStackItem {
2965 path,
2966 is_in_prefix_set: Some(prefix_set_contains(&path)),
2967 },
2968 RlpNodePathStackItem { path: child_path, is_in_prefix_set: None },
2969 ]);
2970 return
2971 }
2972 }
2973 SparseNode::Branch { state_mask, state, blinded_mask, blinded_hashes } => {
2974 if let Some((rlp_node, store_in_db_trie)) = state
2975 .cached_rlp_node()
2976 .zip(state.store_in_db_trie())
2977 .filter(|_| !prefix_set_contains(&path))
2978 {
2979 let node_type =
2980 SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie) };
2981
2982 trace!(
2983 target: "trie::parallel_sparse",
2984 ?path,
2985 ?node_type,
2986 ?rlp_node,
2987 "Adding node to RLP node stack (cached branch)"
2988 );
2989
2990 self.buffers.rlp_node_stack.push(RlpNodeStackItem {
2993 path,
2994 rlp_node: rlp_node.clone(),
2995 node_type,
2996 });
2997 return
2998 }
2999
3000 let retain_updates = update_actions.is_some() && prefix_set_contains(&path);
3001
3002 self.buffers.branch_child_buf.clear();
3003 for bit in state_mask.iter().rev() {
3006 let mut child = path;
3007 child.push_unchecked(bit);
3008
3009 if !blinded_mask.is_bit_set(bit) {
3010 self.buffers.branch_child_buf.push(child);
3011 }
3012 }
3013
3014 self.buffers.branch_value_stack_buf.resize(state_mask.len(), Default::default());
3015
3016 let mut tree_mask = TrieMask::default();
3017 let mut hash_mask = TrieMask::default();
3018 let mut hashes = Vec::new();
3019
3020 let mut path_masks_storage = None;
3022 let mut path_masks =
3023 || *path_masks_storage.get_or_insert_with(|| branch_node_masks.get(&path));
3024
3025 for (i, child_nibble) in state_mask.iter().enumerate().rev() {
3026 let mut child_path = path;
3027 child_path.push_unchecked(child_nibble);
3028
3029 let (child, child_node_type) = if blinded_mask.is_bit_set(child_nibble) {
3030 (
3031 RlpNode::word_rlp(&blinded_hashes[child_nibble as usize]),
3032 SparseNodeType::Hash,
3033 )
3034 } else if self
3035 .buffers
3036 .rlp_node_stack
3037 .last()
3038 .is_some_and(|e| e.path == child_path)
3039 {
3040 let RlpNodeStackItem { path: _, rlp_node, node_type } =
3041 self.buffers.rlp_node_stack.pop().unwrap();
3042
3043 (rlp_node, node_type)
3044 } else {
3045 self.buffers.path_stack.push(RlpNodePathStackItem {
3048 path,
3049 is_in_prefix_set: Some(prefix_set_contains(&path)),
3050 });
3051 self.buffers.path_stack.extend(
3052 self.buffers
3053 .branch_child_buf
3054 .drain(..)
3055 .map(|path| RlpNodePathStackItem { path, is_in_prefix_set: None }),
3056 );
3057 return
3058 };
3059
3060 if retain_updates {
3062 let should_set_tree_mask_bit =
3064 if let Some(store_in_db_trie) = child_node_type.store_in_db_trie() {
3065 store_in_db_trie
3068 } else {
3069 child_node_type.is_hash() &&
3071 path_masks().is_some_and(|masks| {
3072 masks.tree_mask.is_bit_set(child_nibble)
3073 })
3074 };
3075 if should_set_tree_mask_bit {
3076 tree_mask.set_bit(child_nibble);
3077 }
3078 let hash = child.as_hash().filter(|_| {
3082 child_node_type.is_branch() ||
3083 (child_node_type.is_hash() &&
3084 path_masks().is_some_and(|masks| {
3085 masks.hash_mask.is_bit_set(child_nibble)
3086 }))
3087 });
3088 if let Some(hash) = hash {
3089 hash_mask.set_bit(child_nibble);
3090 hashes.push(hash);
3091 }
3092 }
3093
3094 self.buffers.branch_value_stack_buf[i] = child;
3098 }
3099
3100 trace!(
3101 target: "trie::parallel_sparse",
3102 ?path,
3103 ?tree_mask,
3104 ?hash_mask,
3105 "Branch node masks"
3106 );
3107
3108 self.buffers.rlp_buf.clear();
3111 let branch_node_ref =
3112 BranchNodeRef::new(&self.buffers.branch_value_stack_buf, *state_mask);
3113 let rlp_node = branch_node_ref.rlp(&mut self.buffers.rlp_buf);
3114
3115 let store_in_db_trie_value = if let Some(update_actions) =
3118 update_actions.as_mut().filter(|_| retain_updates && !path.is_empty())
3119 {
3120 let store_in_db_trie = !tree_mask.is_empty() || !hash_mask.is_empty();
3121 if store_in_db_trie {
3122 hashes.reverse();
3125 let branch_node =
3126 BranchNodeCompact::new(*state_mask, tree_mask, hash_mask, hashes, None);
3127 update_actions
3128 .push(SparseTrieUpdatesAction::InsertUpdated(path, branch_node));
3129 } else {
3130 let prev_had_masks = path_masks()
3132 .is_some_and(|m| !m.tree_mask.is_empty() || !m.hash_mask.is_empty());
3133 if prev_had_masks {
3134 update_actions.push(SparseTrieUpdatesAction::InsertRemoved(path));
3136 } else {
3137 update_actions.push(SparseTrieUpdatesAction::RemoveUpdated(path));
3139 }
3140 }
3141
3142 store_in_db_trie
3143 } else {
3144 false
3145 };
3146
3147 *state = SparseNodeState::Cached {
3148 rlp_node: rlp_node.clone(),
3149 store_in_db_trie: Some(store_in_db_trie_value),
3150 };
3151
3152 (
3153 rlp_node,
3154 SparseNodeType::Branch { store_in_db_trie: Some(store_in_db_trie_value) },
3155 )
3156 }
3157 };
3158
3159 trace!(
3160 target: "trie::parallel_sparse",
3161 ?path,
3162 ?node_type,
3163 ?rlp_node,
3164 "Adding node to RLP node stack"
3165 );
3166 self.buffers.rlp_node_stack.push(RlpNodeStackItem { path, rlp_node, node_type });
3167 }
3168
3169 fn clear(&mut self) {
3171 self.values.clear();
3172 self.buffers.clear();
3173 }
3174}
3175
3176#[derive(Clone, Debug, PartialEq, Eq, Default)]
3178pub enum LeafUpdateStep {
3179 Continue,
3181 Complete {
3183 inserted_nodes: Vec<Nibbles>,
3185 },
3186 #[default]
3188 NodeNotFound,
3189}
3190
3191impl LeafUpdateStep {
3192 pub const fn complete_with_insertions(inserted_nodes: Vec<Nibbles>) -> Self {
3194 Self::Complete { inserted_nodes }
3195 }
3196}
3197
3198#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3207pub enum SparseSubtrieType {
3208 Upper,
3210 Lower(usize),
3213}
3214
3215impl SparseSubtrieType {
3216 pub const fn path_len_is_upper(len: usize) -> bool {
3221 len < UPPER_TRIE_MAX_DEPTH
3222 }
3223
3224 pub fn from_path(path: &Nibbles) -> Self {
3226 if Self::path_len_is_upper(path.len()) {
3227 Self::Upper
3228 } else {
3229 Self::Lower(path_subtrie_index_unchecked(path))
3230 }
3231 }
3232
3233 pub const fn lower_index(&self) -> Option<usize> {
3235 match self {
3236 Self::Upper => None,
3237 Self::Lower(index) => Some(*index),
3238 }
3239 }
3240}
3241
3242impl Ord for SparseSubtrieType {
3243 fn cmp(&self, other: &Self) -> Ordering {
3246 match (self, other) {
3247 (Self::Upper, Self::Upper) => Ordering::Equal,
3248 (Self::Upper, Self::Lower(_)) => Ordering::Less,
3249 (Self::Lower(_), Self::Upper) => Ordering::Greater,
3250 (Self::Lower(idx_a), Self::Lower(idx_b)) if idx_a == idx_b => Ordering::Equal,
3251 (Self::Lower(idx_a), Self::Lower(idx_b)) => idx_a.cmp(idx_b),
3252 }
3253 }
3254}
3255
3256impl PartialOrd for SparseSubtrieType {
3257 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3258 Some(self.cmp(other))
3259 }
3260}
3261
3262#[derive(Clone, PartialEq, Eq, Debug, Default)]
3266pub struct SparseSubtrieBuffers {
3267 path_stack: Vec<RlpNodePathStackItem>,
3269 rlp_node_stack: Vec<RlpNodeStackItem>,
3271 branch_child_buf: Vec<Nibbles>,
3273 branch_value_stack_buf: Vec<RlpNode>,
3275 rlp_buf: Vec<u8>,
3277}
3278
3279impl SparseSubtrieBuffers {
3280 fn clear(&mut self) {
3282 self.path_stack.clear();
3283 self.rlp_node_stack.clear();
3284 self.branch_child_buf.clear();
3285 self.branch_value_stack_buf.clear();
3286 self.rlp_buf.clear();
3287 }
3288
3289 const fn memory_size(&self) -> usize {
3291 let mut size = core::mem::size_of::<Self>();
3292
3293 size += self.path_stack.capacity() * core::mem::size_of::<RlpNodePathStackItem>();
3294 size += self.rlp_node_stack.capacity() * core::mem::size_of::<RlpNodeStackItem>();
3295 size += self.branch_child_buf.capacity() * core::mem::size_of::<Nibbles>();
3296 size += self.branch_value_stack_buf.capacity() * core::mem::size_of::<RlpNode>();
3297 size += self.rlp_buf.capacity();
3298
3299 size
3300 }
3301}
3302
3303#[derive(Clone, PartialEq, Eq, Debug)]
3305pub struct RlpNodePathStackItem {
3306 pub path: Nibbles,
3308 pub is_in_prefix_set: Option<bool>,
3310}
3311
3312#[derive(Debug)]
3314struct ChangedSubtrie {
3315 index: usize,
3317 subtrie: Box<SparseSubtrie>,
3319 prefix_set: PrefixSet,
3321 update_actions_buf: Option<Vec<SparseTrieUpdatesAction>>,
3324}
3325
3326fn path_subtrie_index_unchecked(path: &Nibbles) -> usize {
3333 debug_assert_eq!(UPPER_TRIE_MAX_DEPTH, 2);
3334 let idx = path.get_byte_unchecked(0) as usize;
3335 unsafe { core::hint::assert_unchecked(idx < NUM_LOWER_SUBTRIES) };
3337 idx
3338}
3339
3340fn is_strict_descendant_in(roots: &[Nibbles], path: &Nibbles) -> bool {
3345 if roots.is_empty() {
3346 return false;
3347 }
3348 debug_assert!(roots.windows(2).all(|w| w[0] <= w[1]), "roots must be sorted by path");
3349 let idx = roots.partition_point(|root| root <= path);
3350 if idx > 0 {
3351 let candidate = &roots[idx - 1];
3352 if path.starts_with(candidate) && path.len() > candidate.len() {
3353 return true;
3354 }
3355 }
3356 false
3357}
3358
3359fn has_retained_descendant(retained: &[Nibbles], prefix: &Nibbles) -> bool {
3363 if retained.is_empty() {
3364 return false;
3365 }
3366 debug_assert!(retained.windows(2).all(|w| w[0] <= w[1]), "retained must be sorted by path");
3367 let idx = retained.partition_point(|path| path < prefix);
3368 idx < retained.len() && retained[idx].starts_with(prefix)
3369}
3370
3371fn starts_with_pruned_in(roots: &[Nibbles], path: &Nibbles) -> bool {
3376 if roots.is_empty() {
3377 return false;
3378 }
3379 debug_assert!(roots.windows(2).all(|w| w[0] <= w[1]), "roots must be sorted by path");
3380 let idx = roots.partition_point(|root| root <= path);
3381 if idx > 0 {
3382 let candidate = &roots[idx - 1];
3383 if path.starts_with(candidate) {
3384 return true;
3385 }
3386 }
3387 false
3388}
3389
3390#[derive(Clone, Debug, Eq, PartialEq)]
3392enum SparseTrieUpdatesAction {
3393 InsertRemoved(Nibbles),
3395 RemoveUpdated(Nibbles),
3398 InsertUpdated(Nibbles, BranchNodeCompact),
3400}
3401
3402#[cfg(test)]
3403mod tests {
3404 use super::{
3405 path_subtrie_index_unchecked, LowerSparseSubtrie, ParallelSparseTrie, SparseSubtrie,
3406 SparseSubtrieType,
3407 };
3408 use crate::{
3409 parallel::ChangedSubtrie, trie::SparseNodeState, LeafLookup, LeafLookupError, SparseNode,
3410 SparseTrie, SparseTrieUpdates,
3411 };
3412 use alloy_primitives::{
3413 b256, hex,
3414 map::{B256Set, HashMap},
3415 B256, U256,
3416 };
3417 use alloy_rlp::{Decodable, Encodable};
3418 use alloy_trie::{proof::AddedRemovedKeys, BranchNodeCompact, Nibbles};
3419 use assert_matches::assert_matches;
3420 use itertools::Itertools;
3421 use proptest::{prelude::*, sample::SizeRange};
3422 use proptest_arbitrary_interop::arb;
3423 use reth_execution_errors::SparseTrieErrorKind;
3424 use reth_primitives_traits::Account;
3425 use reth_provider::{
3426 test_utils::create_test_provider_factory, StorageSettingsCache, TrieWriter,
3427 };
3428 use reth_trie::{
3429 hashed_cursor::{noop::NoopHashedCursor, HashedPostStateCursor},
3430 node_iter::{TrieElement, TrieNodeIter},
3431 trie_cursor::{noop::NoopAccountTrieCursor, TrieCursor, TrieCursorFactory},
3432 walker::TrieWalker,
3433 HashedPostState,
3434 };
3435 use reth_trie_common::{
3436 prefix_set::PrefixSetMut,
3437 proof::{ProofNodes, ProofRetainer},
3438 updates::TrieUpdates,
3439 BranchNodeMasks, BranchNodeMasksMap, BranchNodeRef, BranchNodeV2, ExtensionNode,
3440 HashBuilder, LeafNode, ProofTrieNodeV2, RlpNode, TrieMask, TrieNode, TrieNodeV2,
3441 EMPTY_ROOT_HASH,
3442 };
3443 use reth_trie_db::DatabaseTrieCursorFactory;
3444 use std::collections::{BTreeMap, BTreeSet};
3445
3446 fn pad_nibbles_right(mut nibbles: Nibbles) -> Nibbles {
3448 nibbles.extend(&Nibbles::from_nibbles_unchecked(vec![
3449 0;
3450 B256::len_bytes() * 2 - nibbles.len()
3451 ]));
3452 nibbles
3453 }
3454
3455 fn leaf_key(suffix: impl AsRef<[u8]>, total_len: usize) -> Nibbles {
3458 let suffix = suffix.as_ref();
3459 let mut nibbles = Nibbles::from_nibbles(suffix);
3460 nibbles.extend(&Nibbles::from_nibbles_unchecked(vec![0; total_len - suffix.len()]));
3461 nibbles
3462 }
3463
3464 fn create_account(nonce: u64) -> Account {
3465 Account { nonce, ..Default::default() }
3466 }
3467
3468 fn large_account_value() -> Vec<u8> {
3469 let account = Account {
3470 nonce: 0x123456789abcdef,
3471 balance: U256::from(0x123456789abcdef0123456789abcdef_u128),
3472 ..Default::default()
3473 };
3474 let mut buf = Vec::new();
3475 account.into_trie_account(EMPTY_ROOT_HASH).encode(&mut buf);
3476 buf
3477 }
3478
3479 fn encode_account_value(nonce: u64) -> Vec<u8> {
3480 let account = Account { nonce, ..Default::default() };
3481 let trie_account = account.into_trie_account(EMPTY_ROOT_HASH);
3482 let mut buf = Vec::new();
3483 trie_account.encode(&mut buf);
3484 buf
3485 }
3486
3487 #[derive(Default)]
3489 struct ParallelSparseTrieTestContext;
3490
3491 impl ParallelSparseTrieTestContext {
3492 fn assert_subtrie_exists(&self, trie: &ParallelSparseTrie, path: &Nibbles) {
3494 let idx = path_subtrie_index_unchecked(path);
3495 assert!(
3496 trie.lower_subtries[idx].as_revealed_ref().is_some(),
3497 "Expected lower subtrie at path {path:?} to exist",
3498 );
3499 }
3500
3501 fn get_subtrie<'a>(
3503 &self,
3504 trie: &'a ParallelSparseTrie,
3505 path: &Nibbles,
3506 ) -> &'a SparseSubtrie {
3507 let idx = path_subtrie_index_unchecked(path);
3508 trie.lower_subtries[idx]
3509 .as_revealed_ref()
3510 .unwrap_or_else(|| panic!("Lower subtrie at path {path:?} should exist"))
3511 }
3512
3513 fn assert_subtrie_path(
3515 &self,
3516 trie: &ParallelSparseTrie,
3517 subtrie_prefix: impl AsRef<[u8]>,
3518 expected_path: impl AsRef<[u8]>,
3519 ) {
3520 let subtrie_prefix = Nibbles::from_nibbles(subtrie_prefix);
3521 let expected_path = Nibbles::from_nibbles(expected_path);
3522 let idx = path_subtrie_index_unchecked(&subtrie_prefix);
3523
3524 let subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap_or_else(|| {
3525 panic!("Lower subtrie at prefix {subtrie_prefix:?} should exist")
3526 });
3527
3528 assert_eq!(
3529 subtrie.path, expected_path,
3530 "Subtrie at prefix {subtrie_prefix:?} should have path {expected_path:?}, but has {:?}",
3531 subtrie.path
3532 );
3533 }
3534
3535 fn create_test_leaves(&self, paths: &[&[u8]]) -> Vec<(Nibbles, Vec<u8>)> {
3537 paths
3538 .iter()
3539 .enumerate()
3540 .map(|(i, path)| {
3541 (
3542 pad_nibbles_right(Nibbles::from_nibbles(path)),
3543 encode_account_value(i as u64 + 1),
3544 )
3545 })
3546 .collect()
3547 }
3548
3549 fn create_test_leaf(&self, path: impl AsRef<[u8]>, value_nonce: u64) -> (Nibbles, Vec<u8>) {
3551 (pad_nibbles_right(Nibbles::from_nibbles(path)), encode_account_value(value_nonce))
3552 }
3553
3554 fn update_leaves(
3556 &self,
3557 trie: &mut ParallelSparseTrie,
3558 leaves: impl IntoIterator<Item = (Nibbles, Vec<u8>)>,
3559 ) {
3560 for (path, value) in leaves {
3561 trie.update_leaf(path, value).unwrap();
3562 }
3563 }
3564
3565 fn assert_subtrie<'a>(
3567 &self,
3568 trie: &'a ParallelSparseTrie,
3569 path: Nibbles,
3570 ) -> SubtrieAssertion<'a> {
3571 self.assert_subtrie_exists(trie, &path);
3572 let subtrie = self.get_subtrie(trie, &path);
3573 SubtrieAssertion::new(subtrie)
3574 }
3575
3576 fn assert_upper_subtrie<'a>(&self, trie: &'a ParallelSparseTrie) -> SubtrieAssertion<'a> {
3578 SubtrieAssertion::new(&trie.upper_subtrie)
3579 }
3580
3581 fn assert_with_hash_builder(
3583 &self,
3584 trie: &mut ParallelSparseTrie,
3585 hash_builder_root: B256,
3586 hash_builder_updates: TrieUpdates,
3587 hash_builder_proof_nodes: ProofNodes,
3588 ) {
3589 assert_eq!(trie.root(), hash_builder_root);
3590 pretty_assertions::assert_eq!(
3591 BTreeMap::from_iter(trie.updates_ref().updated_nodes.clone()),
3592 BTreeMap::from_iter(hash_builder_updates.account_nodes)
3593 );
3594 assert_eq_parallel_sparse_trie_proof_nodes(trie, hash_builder_proof_nodes);
3595 }
3596 }
3597
3598 struct SubtrieAssertion<'a> {
3600 subtrie: &'a SparseSubtrie,
3601 }
3602
3603 impl<'a> SubtrieAssertion<'a> {
3604 fn new(subtrie: &'a SparseSubtrie) -> Self {
3605 Self { subtrie }
3606 }
3607
3608 fn has_branch(self, path: &Nibbles, expected_mask_bits: &[u8]) -> Self {
3609 match self.subtrie.nodes.get(path) {
3610 Some(SparseNode::Branch { state_mask, .. }) => {
3611 for bit in expected_mask_bits {
3612 assert!(
3613 state_mask.is_bit_set(*bit),
3614 "Expected branch at {path:?} to have bit {bit} set, instead mask is: {state_mask:?}",
3615 );
3616 }
3617 }
3618 node => panic!("Expected branch node at {path:?}, found {node:?}"),
3619 }
3620 self
3621 }
3622
3623 fn has_leaf(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
3624 match self.subtrie.nodes.get(path) {
3625 Some(SparseNode::Leaf { key, .. }) => {
3626 assert_eq!(
3627 *key, *expected_key,
3628 "Expected leaf at {path:?} to have key {expected_key:?}, found {key:?}",
3629 );
3630 }
3631 node => panic!("Expected leaf node at {path:?}, found {node:?}"),
3632 }
3633 self
3634 }
3635
3636 fn has_extension(self, path: &Nibbles, expected_key: &Nibbles) -> Self {
3637 match self.subtrie.nodes.get(path) {
3638 Some(SparseNode::Extension { key, .. }) => {
3639 assert_eq!(
3640 *key, *expected_key,
3641 "Expected extension at {path:?} to have key {expected_key:?}, found {key:?}",
3642 );
3643 }
3644 node => panic!("Expected extension node at {path:?}, found {node:?}"),
3645 }
3646 self
3647 }
3648
3649 fn has_value(self, path: &Nibbles, expected_value: &[u8]) -> Self {
3650 let actual = self.subtrie.inner.values.get(path);
3651 assert_eq!(
3652 actual.map(|v| v.as_slice()),
3653 Some(expected_value),
3654 "Expected value at {path:?} to be {expected_value:?}, found {actual:?}",
3655 );
3656 self
3657 }
3658
3659 fn has_no_value(self, path: &Nibbles) -> Self {
3660 let actual = self.subtrie.inner.values.get(path);
3661 assert!(actual.is_none(), "Expected no value at {path:?}, but found {actual:?}");
3662 self
3663 }
3664 }
3665
3666 fn create_leaf_node(key: impl AsRef<[u8]>, value_nonce: u64) -> TrieNodeV2 {
3667 TrieNodeV2::Leaf(LeafNode::new(
3668 Nibbles::from_nibbles(key),
3669 encode_account_value(value_nonce),
3670 ))
3671 }
3672
3673 fn create_branch_node(
3674 key: Nibbles,
3675 children_indices: &[u8],
3676 child_hashes: impl IntoIterator<Item = RlpNode>,
3677 ) -> TrieNodeV2 {
3678 let mut stack = Vec::new();
3679 let mut state_mask = TrieMask::default();
3680
3681 for (&idx, hash) in children_indices.iter().zip(child_hashes) {
3682 state_mask.set_bit(idx);
3683 stack.push(hash);
3684 }
3685
3686 let branch_rlp_node = if key.is_empty() {
3687 None
3688 } else {
3689 Some(RlpNode::from_rlp(&alloy_rlp::encode(BranchNodeRef::new(&stack, state_mask))))
3690 };
3691
3692 TrieNodeV2::Branch(BranchNodeV2::new(key, stack, state_mask, branch_rlp_node))
3693 }
3694
3695 fn create_branch_node_with_children(
3696 children_indices: &[u8],
3697 child_hashes: impl IntoIterator<Item = RlpNode>,
3698 ) -> TrieNodeV2 {
3699 create_branch_node(Nibbles::default(), children_indices, child_hashes)
3700 }
3701
3702 fn run_hash_builder(
3707 state: impl IntoIterator<Item = (Nibbles, Account)> + Clone,
3708 trie_cursor: impl TrieCursor,
3709 destroyed_accounts: B256Set,
3710 proof_targets: impl IntoIterator<Item = Nibbles>,
3711 ) -> (B256, TrieUpdates, ProofNodes, HashMap<Nibbles, TrieMask>, HashMap<Nibbles, TrieMask>)
3712 {
3713 let mut account_rlp = Vec::new();
3714
3715 let mut hash_builder = HashBuilder::default()
3716 .with_updates(true)
3717 .with_proof_retainer(ProofRetainer::from_iter(proof_targets).with_added_removed_keys(
3718 Some(AddedRemovedKeys::default().with_assume_added(true)),
3719 ));
3720
3721 let mut prefix_set = PrefixSetMut::default();
3722 prefix_set.extend_keys(state.clone().into_iter().map(|(nibbles, _)| nibbles));
3723 prefix_set.extend_keys(destroyed_accounts.iter().map(Nibbles::unpack));
3724 let walker = TrieWalker::<_>::state_trie(trie_cursor, prefix_set.freeze())
3725 .with_deletions_retained(true);
3726 let hashed_post_state = HashedPostState::default()
3727 .with_accounts(state.into_iter().map(|(nibbles, account)| {
3728 (nibbles.pack().into_inner().unwrap().into(), Some(account))
3729 }))
3730 .into_sorted();
3731 let mut node_iter = TrieNodeIter::state_trie(
3732 walker,
3733 HashedPostStateCursor::new_account(
3734 NoopHashedCursor::<Account>::default(),
3735 &hashed_post_state,
3736 ),
3737 );
3738
3739 while let Some(node) = node_iter.try_next().unwrap() {
3740 match node {
3741 TrieElement::Branch(branch) => {
3742 hash_builder.add_branch(branch.key, branch.value, branch.children_are_in_trie);
3743 }
3744 TrieElement::Leaf(key, account) => {
3745 let account = account.into_trie_account(EMPTY_ROOT_HASH);
3746 account.encode(&mut account_rlp);
3747
3748 hash_builder.add_leaf(Nibbles::unpack(key), &account_rlp);
3749 account_rlp.clear();
3750 }
3751 }
3752 }
3753 let root = hash_builder.root();
3754 let proof_nodes = hash_builder.take_proof_nodes();
3755 let branch_node_hash_masks = hash_builder
3756 .updated_branch_nodes
3757 .clone()
3758 .unwrap_or_default()
3759 .iter()
3760 .map(|(path, node)| (*path, node.hash_mask))
3761 .collect();
3762 let branch_node_tree_masks = hash_builder
3763 .updated_branch_nodes
3764 .clone()
3765 .unwrap_or_default()
3766 .iter()
3767 .map(|(path, node)| (*path, node.tree_mask))
3768 .collect();
3769
3770 let mut trie_updates = TrieUpdates::default();
3771 let removed_keys = node_iter.walker.take_removed_keys();
3772 trie_updates.finalize(hash_builder, removed_keys, destroyed_accounts);
3773
3774 (root, trie_updates, proof_nodes, branch_node_hash_masks, branch_node_tree_masks)
3775 }
3776
3777 fn new_test_trie<Nodes>(nodes: Nodes) -> ParallelSparseTrie
3780 where
3781 Nodes: Iterator<Item = (Nibbles, SparseNode)>,
3782 {
3783 let mut trie = ParallelSparseTrie::default().with_updates(true);
3784
3785 for (path, node) in nodes {
3786 let subtrie = trie.subtrie_for_path_mut(&path);
3787 if let SparseNode::Leaf { key, .. } = &node {
3788 let mut full_key = path;
3789 full_key.extend(key);
3790 subtrie.inner.values.insert(full_key, "LEAF VALUE".into());
3791 }
3792 subtrie.nodes.insert(path, node);
3793 }
3794 trie
3795 }
3796
3797 fn parallel_sparse_trie_nodes(
3798 sparse_trie: &ParallelSparseTrie,
3799 ) -> impl IntoIterator<Item = (&Nibbles, &SparseNode)> {
3800 let lower_sparse_nodes = sparse_trie
3801 .lower_subtries
3802 .iter()
3803 .filter_map(|subtrie| subtrie.as_revealed_ref())
3804 .flat_map(|subtrie| subtrie.nodes.iter());
3805
3806 let upper_sparse_nodes = sparse_trie.upper_subtrie.nodes.iter();
3807
3808 lower_sparse_nodes.chain(upper_sparse_nodes).sorted_by_key(|(path, _)| *path)
3809 }
3810
3811 fn assert_eq_parallel_sparse_trie_proof_nodes(
3814 sparse_trie: &ParallelSparseTrie,
3815 proof_nodes: ProofNodes,
3816 ) {
3817 let proof_nodes = proof_nodes
3818 .into_nodes_sorted()
3819 .into_iter()
3820 .map(|(path, node)| (path, TrieNodeV2::decode(&mut node.as_ref()).unwrap()));
3821
3822 let all_sparse_nodes = parallel_sparse_trie_nodes(sparse_trie);
3823
3824 for ((proof_node_path, proof_node), (sparse_node_path, sparse_node)) in
3825 proof_nodes.zip(all_sparse_nodes)
3826 {
3827 assert_eq!(&proof_node_path, sparse_node_path);
3828
3829 let equals = match (&proof_node, &sparse_node) {
3830 (TrieNodeV2::EmptyRoot, SparseNode::Empty) => true,
3832 (
3834 TrieNodeV2::Branch(BranchNodeV2 { state_mask: proof_state_mask, .. }),
3835 SparseNode::Branch { state_mask: sparse_state_mask, .. },
3836 ) => proof_state_mask == sparse_state_mask,
3837 (
3839 TrieNodeV2::Extension(ExtensionNode { key: proof_key, .. }),
3840 SparseNode::Extension { key: sparse_key, .. },
3841 ) |
3842 (
3844 TrieNodeV2::Leaf(LeafNode { key: proof_key, .. }),
3845 SparseNode::Leaf { key: sparse_key, .. },
3846 ) => proof_key == sparse_key,
3847 (_, SparseNode::Empty) => continue,
3849 _ => false,
3850 };
3851 assert!(
3852 equals,
3853 "path: {proof_node_path:?}\nproof node: {proof_node:?}\nsparse node: {sparse_node:?}"
3854 );
3855 }
3856 }
3857
3858 #[test]
3859 fn test_get_changed_subtries_empty() {
3860 let mut trie = ParallelSparseTrie::default();
3861 let mut prefix_set = PrefixSetMut::from([Nibbles::default()]).freeze();
3862
3863 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3864 assert!(subtries.is_empty());
3865 assert_eq!(unchanged_prefix_set, PrefixSetMut::from(prefix_set.iter().copied()));
3866 }
3867
3868 #[test]
3869 fn test_get_changed_subtries() {
3870 let mut trie = ParallelSparseTrie::default();
3872 let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
3873 let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
3874 let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
3875 let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
3876 let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
3877 let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
3878
3879 trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
3881 trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
3882 trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3);
3883
3884 let unchanged_prefix_set = PrefixSetMut::from([
3885 Nibbles::from_nibbles([0x0]),
3886 Nibbles::from_nibbles([0x2, 0x0, 0x0]),
3887 ]);
3888 let mut prefix_set = PrefixSetMut::from([
3890 Nibbles::from_nibbles([0x1, 0x0, 0x0]),
3892 Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0]),
3893 ]);
3894 prefix_set.extend(unchanged_prefix_set);
3895 let mut prefix_set = prefix_set.freeze();
3896
3897 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3899 assert_eq!(
3900 subtries
3901 .into_iter()
3902 .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
3903 (index, subtrie, prefix_set.iter().copied().collect::<Vec<_>>())
3904 })
3905 .collect::<Vec<_>>(),
3906 vec![(
3907 subtrie_2_index,
3908 subtrie_2,
3909 vec![
3910 Nibbles::from_nibbles([0x1, 0x0, 0x0]),
3911 Nibbles::from_nibbles([0x1, 0x0, 0x1, 0x0])
3912 ]
3913 )]
3914 );
3915 assert_eq!(unchanged_prefix_set, unchanged_prefix_set);
3916 assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_none());
3917
3918 assert_eq!(trie.lower_subtries[subtrie_1_index], LowerSparseSubtrie::Revealed(subtrie_1));
3920 }
3921
3922 #[test]
3923 fn test_get_changed_subtries_all() {
3924 let mut trie = ParallelSparseTrie::default();
3926 let subtrie_1 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
3927 let subtrie_1_index = path_subtrie_index_unchecked(&subtrie_1.path);
3928 let subtrie_2 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x1, 0x0])));
3929 let subtrie_2_index = path_subtrie_index_unchecked(&subtrie_2.path);
3930 let subtrie_3 = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x3, 0x0])));
3931 let subtrie_3_index = path_subtrie_index_unchecked(&subtrie_3.path);
3932
3933 trie.lower_subtries[subtrie_1_index] = LowerSparseSubtrie::Revealed(subtrie_1.clone());
3935 trie.lower_subtries[subtrie_2_index] = LowerSparseSubtrie::Revealed(subtrie_2.clone());
3936 trie.lower_subtries[subtrie_3_index] = LowerSparseSubtrie::Revealed(subtrie_3.clone());
3937
3938 let mut prefix_set = PrefixSetMut::all().freeze();
3940
3941 let (subtries, unchanged_prefix_set) = trie.take_changed_lower_subtries(&mut prefix_set);
3943 assert_eq!(
3944 subtries
3945 .into_iter()
3946 .map(|ChangedSubtrie { index, subtrie, prefix_set, .. }| {
3947 (index, subtrie, prefix_set.all())
3948 })
3949 .collect::<Vec<_>>(),
3950 vec![
3951 (subtrie_1_index, subtrie_1, true),
3952 (subtrie_2_index, subtrie_2, true),
3953 (subtrie_3_index, subtrie_3, true)
3954 ]
3955 );
3956 assert_eq!(unchanged_prefix_set, PrefixSetMut::all());
3957
3958 assert!(trie.lower_subtries.iter().all(|subtrie| subtrie.as_revealed_ref().is_none()));
3959 }
3960
3961 #[test]
3962 fn test_sparse_subtrie_type() {
3963 assert_eq!(SparseSubtrieType::from_path(&Nibbles::new()), SparseSubtrieType::Upper);
3964 assert_eq!(
3965 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0])),
3966 SparseSubtrieType::Upper
3967 );
3968 assert_eq!(
3969 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15])),
3970 SparseSubtrieType::Upper
3971 );
3972 assert_eq!(
3973 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0])),
3974 SparseSubtrieType::Lower(0)
3975 );
3976 assert_eq!(
3977 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 0, 0])),
3978 SparseSubtrieType::Lower(0)
3979 );
3980 assert_eq!(
3981 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1])),
3982 SparseSubtrieType::Lower(1)
3983 );
3984 assert_eq!(
3985 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 1, 0])),
3986 SparseSubtrieType::Lower(1)
3987 );
3988 assert_eq!(
3989 SparseSubtrieType::from_path(&Nibbles::from_nibbles([0, 15])),
3990 SparseSubtrieType::Lower(15)
3991 );
3992 assert_eq!(
3993 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 0])),
3994 SparseSubtrieType::Lower(240)
3995 );
3996 assert_eq!(
3997 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 1])),
3998 SparseSubtrieType::Lower(241)
3999 );
4000 assert_eq!(
4001 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15])),
4002 SparseSubtrieType::Lower(255)
4003 );
4004 assert_eq!(
4005 SparseSubtrieType::from_path(&Nibbles::from_nibbles([15, 15, 15])),
4006 SparseSubtrieType::Lower(255)
4007 );
4008 }
4009
4010 #[test]
4011 fn test_reveal_node_leaves() {
4012 let root_branch =
4015 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4016 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4017
4018 {
4019 let path = Nibbles::from_nibbles([0x1]);
4020 let node = create_leaf_node([0x2, 0x3], 42);
4021 let masks = None;
4022
4023 trie.reveal_nodes(&mut [ProofTrieNodeV2 { path, node, masks }]).unwrap();
4024
4025 assert_matches!(
4026 trie.upper_subtrie.nodes.get(&path),
4027 Some(SparseNode::Leaf { key, state: SparseNodeState::Cached { .. } })
4028 if key == &Nibbles::from_nibbles([0x2, 0x3])
4029 );
4030
4031 let full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4032 assert_eq!(
4033 trie.upper_subtrie.inner.values.get(&full_path),
4034 Some(&encode_account_value(42))
4035 );
4036 }
4037
4038 let root_branch =
4043 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4044 let branch_at_1 =
4045 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xBB))]);
4046 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4047 trie.reveal_nodes(&mut [ProofTrieNodeV2 {
4048 path: Nibbles::from_nibbles([0x1]),
4049 node: branch_at_1,
4050 masks: None,
4051 }])
4052 .unwrap();
4053
4054 {
4055 let path = Nibbles::from_nibbles([0x1, 0x2]);
4056 let node = create_leaf_node([0x3, 0x4], 42);
4057 let masks = None;
4058
4059 trie.reveal_nodes(&mut [ProofTrieNodeV2 { path, node, masks }]).unwrap();
4060
4061 let idx = path_subtrie_index_unchecked(&path);
4063 assert!(trie.lower_subtries[idx].as_revealed_ref().is_some());
4064
4065 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4067 assert_eq!(lower_subtrie.path, path);
4068
4069 assert_matches!(
4070 lower_subtrie.nodes.get(&path),
4071 Some(SparseNode::Leaf { key, state: SparseNodeState::Cached { .. } })
4072 if key == &Nibbles::from_nibbles([0x3, 0x4])
4073 );
4074 }
4075
4076 {
4079 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4080 let node = create_leaf_node([0x4, 0x5], 42);
4081 let masks = None;
4082
4083 trie.reveal_nodes(&mut [ProofTrieNodeV2 { path, node, masks }]).unwrap();
4084
4085 let idx = path_subtrie_index_unchecked(&path);
4087 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4088 assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2]));
4089 }
4090 }
4091
4092 #[test]
4093 fn test_reveal_node_branch_all_upper() {
4094 let path = Nibbles::new();
4095 let child_hashes = [
4096 RlpNode::word_rlp(&B256::repeat_byte(0x11)),
4097 RlpNode::word_rlp(&B256::repeat_byte(0x22)),
4098 ];
4099 let node = create_branch_node_with_children(&[0x0, 0x5], child_hashes.clone());
4100 let masks = None;
4101 let trie = ParallelSparseTrie::from_root(node, masks, true).unwrap();
4102
4103 assert_eq!(
4105 trie.upper_subtrie.nodes.get(&path).unwrap(),
4106 &SparseNode::new_branch(
4107 0b0000000000100001.into(),
4108 &[(0, child_hashes[0].as_hash().unwrap()), (5, child_hashes[1].as_hash().unwrap())]
4109 )
4110 );
4111
4112 let child_path_0 = Nibbles::from_nibbles([0x0]);
4114 let child_path_5 = Nibbles::from_nibbles([0x5]);
4115 assert!(!trie.upper_subtrie.nodes.contains_key(&child_path_0));
4116 assert!(!trie.upper_subtrie.nodes.contains_key(&child_path_5));
4117 }
4118
4119 #[test]
4120 fn test_reveal_node_branch_cross_level() {
4121 let root_branch =
4123 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
4124 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4125
4126 let path = Nibbles::from_nibbles([0x1]); let child_hashes = [
4128 RlpNode::word_rlp(&B256::repeat_byte(0x33)),
4129 RlpNode::word_rlp(&B256::repeat_byte(0x44)),
4130 RlpNode::word_rlp(&B256::repeat_byte(0x55)),
4131 ];
4132 let node = create_branch_node_with_children(&[0x0, 0x7, 0xf], child_hashes.clone());
4133 let masks = None;
4134
4135 trie.reveal_nodes(&mut [ProofTrieNodeV2 { path, node, masks }]).unwrap();
4136
4137 assert_eq!(
4139 trie.upper_subtrie.nodes.get(&path).unwrap(),
4140 &SparseNode::new_branch(
4141 0b1000000010000001.into(),
4142 &[
4143 (0x0, child_hashes[0].as_hash().unwrap()),
4144 (0x7, child_hashes[1].as_hash().unwrap()),
4145 (0xf, child_hashes[2].as_hash().unwrap())
4146 ]
4147 )
4148 .with_state(SparseNodeState::Cached {
4149 rlp_node: RlpNode::word_rlp(&B256::repeat_byte(0xAA)),
4150 store_in_db_trie: Some(false),
4151 })
4152 );
4153
4154 let child_paths = [
4156 Nibbles::from_nibbles([0x1, 0x0]),
4157 Nibbles::from_nibbles([0x1, 0x7]),
4158 Nibbles::from_nibbles([0x1, 0xf]),
4159 ];
4160
4161 let mut children = child_paths
4162 .iter()
4163 .map(|path| ProofTrieNodeV2 {
4164 path: *path,
4165 node: create_leaf_node([0x0], 1),
4166 masks: None,
4167 })
4168 .collect::<Vec<_>>();
4169
4170 trie.reveal_nodes(&mut children).unwrap();
4171
4172 assert_matches!(
4174 trie.upper_subtrie.nodes.get(&path),
4175 Some(&SparseNode::Branch {
4176 state_mask,
4177 state: SparseNodeState::Cached { ref rlp_node, store_in_db_trie: Some(false) },
4178 blinded_mask,
4179 ..
4180 }) if state_mask == 0b1000000010000001.into() && blinded_mask.is_empty() && *rlp_node == RlpNode::word_rlp(&B256::repeat_byte(0xAA))
4181 );
4182
4183 for (i, child_path) in child_paths.iter().enumerate() {
4184 let idx = path_subtrie_index_unchecked(child_path);
4185 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
4186 assert_eq!(&lower_subtrie.path, child_path);
4187 assert_eq!(
4188 lower_subtrie.nodes.get(child_path),
4189 Some(&SparseNode::Leaf {
4190 key: Nibbles::from_nibbles([0x0]),
4191 state: SparseNodeState::Cached {
4192 rlp_node: child_hashes[i].clone(),
4193 store_in_db_trie: Some(false)
4194 }
4195 })
4196 );
4197 }
4198 }
4199
4200 #[test]
4201 fn test_update_subtrie_hashes_prefix_set_matching() {
4202 let root_branch = create_branch_node_with_children(
4205 &[0x0, 0x3],
4206 [
4207 RlpNode::word_rlp(&B256::repeat_byte(0xAA)),
4208 RlpNode::word_rlp(&B256::repeat_byte(0xBB)),
4209 ],
4210 );
4211 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
4212
4213 let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
4215 let leaf_1_path = leaf_1_full_path.slice(..2);
4216 let leaf_1_key = leaf_1_full_path.slice(2..);
4217 let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 1], vec![0; 62]].concat());
4218 let leaf_2_path = leaf_2_full_path.slice(..2);
4219 let leaf_2_key = leaf_2_full_path.slice(2..);
4220 let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 2], vec![0; 62]].concat());
4221 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), 1);
4222 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), 2);
4223
4224 let child_hashes = [
4228 RlpNode::word_rlp(&B256::repeat_byte(0x00)),
4229 RlpNode::word_rlp(&B256::repeat_byte(0x11)),
4230 ];
4231 let branch_path = Nibbles::from_nibbles([0x0]);
4232 let branch_node = create_branch_node_with_children(&[0x0, 0x1], child_hashes);
4233
4234 trie.reveal_nodes(&mut [
4236 ProofTrieNodeV2 { path: branch_path, node: branch_node, masks: None },
4237 ProofTrieNodeV2 { path: leaf_1_path, node: leaf_1, masks: None },
4238 ProofTrieNodeV2 { path: leaf_2_path, node: leaf_2, masks: None },
4239 ])
4240 .unwrap();
4241
4242 trie.update_leaf(leaf_3_full_path, encode_account_value(3)).unwrap();
4245
4246 let subtrie_1_index = SparseSubtrieType::from_path(&leaf_1_path).lower_index().unwrap();
4248 let subtrie_2_index = SparseSubtrieType::from_path(&leaf_2_path).lower_index().unwrap();
4249 let leaf_3_path = leaf_3_full_path.slice(..2);
4250 let subtrie_3_index = SparseSubtrieType::from_path(&leaf_3_path).lower_index().unwrap();
4251
4252 let mut unchanged_prefix_set = PrefixSetMut::from([
4253 Nibbles::from_nibbles([0x0]),
4254 leaf_2_full_path,
4255 Nibbles::from_nibbles([0x3, 0x0, 0x0]),
4256 ]);
4257 let mut prefix_set = PrefixSetMut::from([
4259 Nibbles::from_nibbles([0x0, 0x1, 0x0]),
4261 Nibbles::from_nibbles([0x0, 0x1, 0x1, 0x0]),
4262 ]);
4263 prefix_set.extend(unchanged_prefix_set.clone());
4264 trie.prefix_set = prefix_set;
4265
4266 trie.update_subtrie_hashes();
4268
4269 unchanged_prefix_set.insert(leaf_3_full_path);
4273
4274 assert_eq!(
4276 trie.prefix_set.clone().freeze().into_iter().collect::<Vec<_>>(),
4277 unchanged_prefix_set.freeze().into_iter().collect::<Vec<_>>()
4278 );
4279 assert!(trie.lower_subtries[subtrie_1_index].as_revealed_ref().is_some());
4281 assert!(trie.lower_subtries[subtrie_2_index].as_revealed_ref().is_some());
4282 assert!(trie.lower_subtries[subtrie_3_index].as_revealed_ref().is_some());
4283 }
4284
4285 #[test]
4286 fn test_subtrie_update_hashes() {
4287 let mut subtrie = Box::new(SparseSubtrie::new(Nibbles::from_nibbles([0x0, 0x0])));
4288
4289 let leaf_1_full_path = Nibbles::from_nibbles([0; 64]);
4291 let leaf_1_path = leaf_1_full_path.slice(..5);
4292 let leaf_1_key = leaf_1_full_path.slice(5..);
4293 let leaf_2_full_path = Nibbles::from_nibbles([vec![0, 0, 0, 0, 1], vec![0; 59]].concat());
4294 let leaf_2_path = leaf_2_full_path.slice(..5);
4295 let leaf_2_key = leaf_2_full_path.slice(5..);
4296 let leaf_3_full_path = Nibbles::from_nibbles([vec![0, 0, 1], vec![0; 61]].concat());
4297 let leaf_3_path = leaf_3_full_path.slice(..3);
4298 let leaf_3_key = leaf_3_full_path.slice(3..);
4299
4300 let account_1 = create_account(1);
4301 let account_2 = create_account(2);
4302 let account_3 = create_account(3);
4303 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
4304 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
4305 let leaf_3 = create_leaf_node(leaf_3_key.to_vec(), account_3.nonce);
4306
4307 let extension_path = Nibbles::from_nibbles([0, 0, 0]);
4309 let branch_1_path = Nibbles::from_nibbles([0, 0, 0, 0]);
4310 let branch_1 = create_branch_node(
4311 Nibbles::from_nibbles([0]),
4312 &[0, 1],
4313 vec![
4314 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
4315 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
4316 ],
4317 );
4318
4319 let branch_2_path = Nibbles::from_nibbles([0, 0]);
4321 let branch_2 = create_branch_node_with_children(
4322 &[0, 1],
4323 vec![
4324 RlpNode::from_rlp(&alloy_rlp::encode(&branch_1)),
4325 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_3)),
4326 ],
4327 );
4328
4329 subtrie.reveal_node(branch_2_path, &branch_2, None, None).unwrap();
4331 subtrie.reveal_node(extension_path, &branch_1, None, None).unwrap();
4332 subtrie.reveal_node(leaf_1_path, &leaf_1, None, None).unwrap();
4333 subtrie.reveal_node(leaf_2_path, &leaf_2, None, None).unwrap();
4334 subtrie.reveal_node(leaf_3_path, &leaf_3, None, None).unwrap();
4335
4336 let (_, _, proof_nodes, _, _) = run_hash_builder(
4338 [
4339 (leaf_1_full_path, account_1),
4340 (leaf_2_full_path, account_2),
4341 (leaf_3_full_path, account_3),
4342 ],
4343 NoopAccountTrieCursor::default(),
4344 Default::default(),
4345 [extension_path, branch_2_path, leaf_1_full_path, leaf_2_full_path, leaf_3_full_path],
4346 );
4347
4348 subtrie.update_hashes(
4350 &mut PrefixSetMut::from([leaf_1_full_path, leaf_2_full_path, leaf_3_full_path])
4351 .freeze(),
4352 &mut None,
4353 &BranchNodeMasksMap::default(),
4354 );
4355
4356 let hash_builder_branch_1_hash =
4358 RlpNode::from_rlp(proof_nodes.get(&branch_1_path).unwrap().as_ref()).as_hash().unwrap();
4359 let subtrie_branch_1_hash =
4360 subtrie.nodes.get(&branch_1_path).unwrap().cached_hash().unwrap();
4361 assert_eq!(hash_builder_branch_1_hash, subtrie_branch_1_hash);
4362
4363 let hash_builder_extension_hash =
4364 RlpNode::from_rlp(proof_nodes.get(&extension_path).unwrap().as_ref())
4365 .as_hash()
4366 .unwrap();
4367 let subtrie_extension_hash =
4368 subtrie.nodes.get(&extension_path).unwrap().cached_hash().unwrap();
4369 assert_eq!(hash_builder_extension_hash, subtrie_extension_hash);
4370
4371 let hash_builder_branch_2_hash =
4372 RlpNode::from_rlp(proof_nodes.get(&branch_2_path).unwrap().as_ref()).as_hash().unwrap();
4373 let subtrie_branch_2_hash =
4374 subtrie.nodes.get(&branch_2_path).unwrap().cached_hash().unwrap();
4375 assert_eq!(hash_builder_branch_2_hash, subtrie_branch_2_hash);
4376
4377 let subtrie_leaf_1_hash = subtrie.nodes.get(&leaf_1_path).unwrap().cached_hash().unwrap();
4378 let hash_builder_leaf_1_hash =
4379 RlpNode::from_rlp(proof_nodes.get(&leaf_1_path).unwrap().as_ref()).as_hash().unwrap();
4380 assert_eq!(hash_builder_leaf_1_hash, subtrie_leaf_1_hash);
4381
4382 let hash_builder_leaf_2_hash =
4383 RlpNode::from_rlp(proof_nodes.get(&leaf_2_path).unwrap().as_ref()).as_hash().unwrap();
4384 let subtrie_leaf_2_hash = subtrie.nodes.get(&leaf_2_path).unwrap().cached_hash().unwrap();
4385 assert_eq!(hash_builder_leaf_2_hash, subtrie_leaf_2_hash);
4386
4387 let hash_builder_leaf_3_hash =
4388 RlpNode::from_rlp(proof_nodes.get(&leaf_3_path).unwrap().as_ref()).as_hash().unwrap();
4389 let subtrie_leaf_3_hash = subtrie.nodes.get(&leaf_3_path).unwrap().cached_hash().unwrap();
4390 assert_eq!(hash_builder_leaf_3_hash, subtrie_leaf_3_hash);
4391 }
4392
4393 #[test]
4394 fn test_remove_leaf_branch_becomes_extension() {
4395 let mut trie = new_test_trie(
4407 [
4408 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4409 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b1001), &[])),
4410 (
4411 Nibbles::from_nibbles([0x5, 0x0]),
4412 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3])),
4413 ),
4414 (
4415 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
4416 SparseNode::new_branch(TrieMask::new(0b0101), &[]),
4417 ),
4418 (
4419 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
4420 SparseNode::new_leaf(leaf_key([], 59)),
4421 ),
4422 (
4423 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
4424 SparseNode::new_leaf(leaf_key([], 59)),
4425 ),
4426 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_leaf(leaf_key([0x7], 62))),
4427 ]
4428 .into_iter(),
4429 );
4430
4431 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x7]));
4433 trie.remove_leaf(&leaf_full_path).unwrap();
4434
4435 let upper_subtrie = &trie.upper_subtrie;
4436 let lower_subtrie_50 = trie.lower_subtries[0x50].as_revealed_ref().unwrap();
4437
4438 assert_matches!(trie.lower_subtries[0x53].as_revealed_ref(), None);
4441
4442 assert_matches!(
4445 upper_subtrie.nodes.get(&Nibbles::from_nibbles([])),
4446 Some(SparseNode::Extension{ key, ..})
4447 if key == &Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])
4448 );
4449 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
4450 assert_matches!(lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0])), None);
4451 assert_matches!(
4452 lower_subtrie_50.nodes.get(&Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3])),
4453 Some(SparseNode::Branch{ state_mask, .. })
4454 if *state_mask == 0b0101.into()
4455 );
4456 }
4457
4458 #[test]
4459 fn test_remove_leaf_branch_becomes_leaf() {
4460 let mut trie = new_test_trie(
4468 [
4469 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0011), &[])),
4470 (Nibbles::from_nibbles([0x0]), SparseNode::new_leaf(leaf_key([0x1, 0x2], 63))),
4471 (Nibbles::from_nibbles([0x1]), SparseNode::new_leaf(leaf_key([0x3, 0x4], 63))),
4472 ]
4473 .into_iter(),
4474 );
4475
4476 if let Some(updates) = trie.updates.as_mut() {
4478 updates
4479 .updated_nodes
4480 .insert(Nibbles::default(), BranchNodeCompact::new(0b11, 0, 0, vec![], None));
4481 }
4482
4483 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0x1, 0x2]));
4485 trie.remove_leaf(&leaf_full_path).unwrap();
4486
4487 let upper_subtrie = &trie.upper_subtrie;
4488
4489 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4491
4492 assert_matches!(
4494 upper_subtrie.nodes.get(&Nibbles::default()),
4495 Some(SparseNode::Leaf{ key, ..})
4496 if key == &pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x3, 0x4]))
4497 );
4498
4499 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
4501 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])), None);
4503
4504 let updates = trie.updates.as_ref().unwrap();
4506
4507 assert!(updates.removed_nodes.contains(&Nibbles::default()));
4509
4510 assert!(!updates.updated_nodes.contains_key(&Nibbles::default()));
4512 }
4513
4514 #[test]
4515 fn test_remove_leaf_extension_becomes_leaf() {
4516 let mut trie = new_test_trie(
4525 [
4526 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
4527 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(TrieMask::new(0b0011), &[])),
4528 (Nibbles::from_nibbles([0x5, 0x0]), SparseNode::new_leaf(leaf_key([0x1, 0x2], 62))),
4529 (Nibbles::from_nibbles([0x5, 0x1]), SparseNode::new_leaf(leaf_key([0x3, 0x4], 62))),
4530 ]
4531 .into_iter(),
4532 );
4533
4534 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x0, 0x1, 0x2]));
4536 trie.remove_leaf(&leaf_full_path).unwrap();
4537
4538 let upper_subtrie = &trie.upper_subtrie;
4539
4540 assert_matches!(trie.lower_subtries[0x50].as_revealed_ref(), None);
4544 assert_matches!(trie.lower_subtries[0x51].as_revealed_ref(), None);
4545
4546 let other_leaf_full_value = pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4]));
4548 assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
4549
4550 assert_matches!(
4552 upper_subtrie.nodes.get(&Nibbles::default()),
4553 Some(SparseNode::Leaf{ key, ..})
4554 if key == &pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x1, 0x3, 0x4]))
4555 );
4556
4557 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x5])), None);
4559 }
4560
4561 #[test]
4562 fn test_remove_leaf_branch_on_branch() {
4563 let mut trie = new_test_trie(
4573 [
4574 (Nibbles::default(), SparseNode::new_branch(TrieMask::new(0b0101), &[])),
4575 (Nibbles::from_nibbles([0x0]), SparseNode::new_leaf(leaf_key([0x1, 0x2], 63))),
4576 (Nibbles::from_nibbles([0x2]), SparseNode::new_branch(TrieMask::new(0b0011), &[])),
4577 (Nibbles::from_nibbles([0x2, 0x0]), SparseNode::new_leaf(leaf_key([0x3, 0x4], 62))),
4578 (Nibbles::from_nibbles([0x2, 0x1]), SparseNode::new_leaf(leaf_key([0x5, 0x6], 62))),
4579 ]
4580 .into_iter(),
4581 );
4582
4583 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x2, 0x0, 0x3, 0x4]));
4585 trie.remove_leaf(&leaf_full_path).unwrap();
4586
4587 let upper_subtrie = &trie.upper_subtrie;
4588
4589 assert_matches!(trie.lower_subtries[0x20].as_revealed_ref(), None);
4593 assert_matches!(trie.lower_subtries[0x21].as_revealed_ref(), None);
4594
4595 let other_leaf_full_value = pad_nibbles_right(Nibbles::from_nibbles([0x2, 0x1, 0x5, 0x6]));
4597 assert_matches!(upper_subtrie.inner.values.get(&other_leaf_full_value), Some(_));
4598
4599 assert_matches!(
4601 upper_subtrie.nodes.get(&Nibbles::default()),
4602 Some(SparseNode::Branch{ state_mask, .. })
4603 if *state_mask == 0b0101.into()
4604 );
4605
4606 assert_matches!(
4608 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x2])),
4609 Some(SparseNode::Leaf{ key, ..})
4610 if key == &leaf_key([0x1, 0x5, 0x6], 63)
4611 );
4612 }
4613
4614 #[test]
4615 fn test_remove_leaf_lower_subtrie_root_path_update() {
4616 let mut trie = new_test_trie(
4630 [
4631 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x1, 0x2, 0x3]))),
4632 (
4633 Nibbles::from_nibbles([0x1, 0x2, 0x3]),
4634 SparseNode::new_branch(TrieMask::new(0b0011000), &[]),
4635 ),
4636 (
4637 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]),
4638 SparseNode::new_leaf(leaf_key([], 60)),
4639 ),
4640 (
4641 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]),
4642 SparseNode::new_ext(Nibbles::from_nibbles([0x5])),
4643 ),
4644 (
4645 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]),
4646 SparseNode::new_branch(TrieMask::new(0b0011), &[]),
4647 ),
4648 (
4649 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x0]),
4650 SparseNode::new_leaf(leaf_key([], 58)),
4651 ),
4652 (
4653 Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x1]),
4654 SparseNode::new_leaf(leaf_key([], 58)),
4655 ),
4656 ]
4657 .into_iter(),
4658 );
4659
4660 let lower_subtrie_root_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
4662 assert_matches!(
4663 trie.lower_subtrie_for_path_mut(&lower_subtrie_root_path),
4664 Some(subtrie)
4665 if subtrie.path == lower_subtrie_root_path
4666 );
4667
4668 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x3]));
4670 trie.remove_leaf(&leaf_full_path).unwrap();
4671
4672 let lower_subtrie = trie.lower_subtries[0x12].as_revealed_ref().unwrap();
4677 assert_eq!(lower_subtrie.path, Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]));
4678
4679 assert_matches!(
4681 trie.upper_subtrie.nodes.get(&Nibbles::default()),
4682 Some(SparseNode::Extension { key, .. })
4683 if key == &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])
4684 );
4685
4686 assert_matches!(
4688 lower_subtrie.nodes.get(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])),
4689 Some(SparseNode::Branch { state_mask, .. })
4690 if state_mask == &TrieMask::new(0b0011)
4691 );
4692 }
4693
4694 #[test]
4695 fn test_remove_leaf_remaining_child_needs_reveal() {
4696 let mut trie = new_test_trie(
4704 [
4705 (
4706 Nibbles::default(),
4707 SparseNode::new_branch(
4708 TrieMask::new(0b0011),
4709 &[(0x1, B256::repeat_byte(0xab))],
4710 ),
4711 ),
4712 (Nibbles::from_nibbles([0x0]), SparseNode::new_leaf(leaf_key([0x1, 0x2], 63))),
4713 ]
4714 .into_iter(),
4715 );
4716
4717 let revealed_leaf = create_leaf_node(leaf_key([0x3, 0x4], 63).to_vec(), 42);
4719 let mut encoded = Vec::new();
4720 revealed_leaf.encode(&mut encoded);
4721
4722 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0x1, 0x2]));
4725 let Err(err) = trie.remove_leaf(&leaf_full_path) else {
4726 panic!("expected error");
4727 };
4728 assert_matches!(err.kind(), SparseTrieErrorKind::BlindedNode(path) if *path == Nibbles::from_nibbles([0x1]));
4729
4730 trie.reveal_nodes(&mut [ProofTrieNodeV2 {
4732 path: Nibbles::from_nibbles([0x1]),
4733 node: revealed_leaf,
4734 masks: None,
4735 }])
4736 .unwrap();
4737 trie.remove_leaf(&leaf_full_path).unwrap();
4738
4739 let upper_subtrie = &trie.upper_subtrie;
4740
4741 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4743
4744 assert_matches!(
4746 upper_subtrie.nodes.get(&Nibbles::default()),
4747 Some(SparseNode::Leaf{ key, ..})
4748 if key == &pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x3, 0x4]))
4749 );
4750
4751 assert_matches!(upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])), None);
4753 }
4754
4755 #[test]
4756 fn test_remove_leaf_root() {
4757 let mut trie = new_test_trie(core::iter::once((
4763 Nibbles::default(),
4764 SparseNode::new_leaf(pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3]))),
4765 )));
4766
4767 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3]));
4769 trie.remove_leaf(&leaf_full_path).unwrap();
4770
4771 let upper_subtrie = &trie.upper_subtrie;
4772
4773 assert_matches!(upper_subtrie.inner.values.get(&leaf_full_path), None);
4775
4776 assert_matches!(upper_subtrie.nodes.get(&Nibbles::default()), Some(SparseNode::Empty));
4778 }
4779
4780 #[test]
4781 fn test_remove_leaf_unsets_hash_along_path() {
4782 let make_revealed = |hash: B256| SparseNodeState::Cached {
4797 rlp_node: RlpNode::word_rlp(&hash),
4798 store_in_db_trie: None,
4799 };
4800 let mut trie = new_test_trie(
4801 [
4802 (
4803 Nibbles::default(),
4804 SparseNode::Branch {
4805 state_mask: TrieMask::new(0b0011),
4806 state: make_revealed(B256::repeat_byte(0x10)),
4807 blinded_mask: Default::default(),
4808 blinded_hashes: Default::default(),
4809 },
4810 ),
4811 (
4812 Nibbles::from_nibbles([0x0]),
4813 SparseNode::Extension {
4814 key: Nibbles::from_nibbles([0x1]),
4815 state: make_revealed(B256::repeat_byte(0x20)),
4816 },
4817 ),
4818 (
4819 Nibbles::from_nibbles([0x0, 0x1]),
4820 SparseNode::Branch {
4821 state_mask: TrieMask::new(0b11100),
4822 state: make_revealed(B256::repeat_byte(0x30)),
4823 blinded_mask: Default::default(),
4824 blinded_hashes: Default::default(),
4825 },
4826 ),
4827 (
4828 Nibbles::from_nibbles([0x0, 0x1, 0x2]),
4829 SparseNode::Leaf {
4830 key: leaf_key([0x3, 0x4], 61),
4831 state: make_revealed(B256::repeat_byte(0x40)),
4832 },
4833 ),
4834 (
4835 Nibbles::from_nibbles([0x0, 0x1, 0x3]),
4836 SparseNode::Leaf {
4837 key: leaf_key([0x5, 0x6], 61),
4838 state: make_revealed(B256::repeat_byte(0x50)),
4839 },
4840 ),
4841 (
4842 Nibbles::from_nibbles([0x0, 0x1, 0x4]),
4843 SparseNode::Leaf {
4844 key: leaf_key([0x6, 0x7], 61),
4845 state: make_revealed(B256::repeat_byte(0x60)),
4846 },
4847 ),
4848 (
4849 Nibbles::from_nibbles([0x1]),
4850 SparseNode::Leaf {
4851 key: leaf_key([0x7, 0x8], 63),
4852 state: make_revealed(B256::repeat_byte(0x70)),
4853 },
4854 ),
4855 ]
4856 .into_iter(),
4857 );
4858
4859 trie.remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4, 0xF])))
4861 .unwrap();
4862 for (path, node) in trie.all_nodes() {
4863 assert!(node.cached_hash().is_some(), "path {path:?} should still have a hash");
4864 }
4865
4866 let leaf_full_path = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0x1, 0x2, 0x3, 0x4]));
4868 trie.remove_leaf(&leaf_full_path).unwrap();
4869
4870 let upper_subtrie = &trie.upper_subtrie;
4871 let lower_subtrie_10 = trie.lower_subtries[0x01].as_revealed_ref().unwrap();
4872
4873 assert_matches!(
4875 upper_subtrie.nodes.get(&Nibbles::default()),
4876 Some(SparseNode::Branch { state: SparseNodeState::Dirty, .. })
4877 );
4878 assert_matches!(
4879 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x0])),
4880 Some(SparseNode::Extension { state: SparseNodeState::Dirty, .. })
4881 );
4882 assert_matches!(
4883 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1])),
4884 Some(SparseNode::Branch { state: SparseNodeState::Dirty, .. })
4885 );
4886
4887 assert_matches!(
4889 upper_subtrie.nodes.get(&Nibbles::from_nibbles([0x1])),
4890 Some(SparseNode::Leaf { state: SparseNodeState::Cached { .. }, .. })
4891 );
4892 assert_matches!(
4893 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x3])),
4894 Some(SparseNode::Leaf { state: SparseNodeState::Cached { .. }, .. })
4895 );
4896 assert_matches!(
4897 lower_subtrie_10.nodes.get(&Nibbles::from_nibbles([0x0, 0x1, 0x4])),
4898 Some(SparseNode::Leaf { state: SparseNodeState::Cached { .. }, .. })
4899 );
4900 }
4901
4902 #[test]
4903 fn test_parallel_sparse_trie_root() {
4904 let extension_path = Nibbles::new();
4907 let extension_key = Nibbles::from_nibbles([0x2]);
4908
4909 let branch_path = Nibbles::from_nibbles([0x2]);
4911
4912 let leaf_1_path = Nibbles::from_nibbles([0x2, 0x0]);
4914 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());
4916
4917 let leaf_2_path = Nibbles::from_nibbles([0x2, 0x1]);
4918 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());
4920
4921 let account_1 = create_account(1);
4923 let account_2 = create_account(2);
4924
4925 let leaf_1 = create_leaf_node(leaf_1_key.to_vec(), account_1.nonce);
4927 let leaf_2 = create_leaf_node(leaf_2_key.to_vec(), account_2.nonce);
4928
4929 let branch = create_branch_node(
4931 extension_key,
4932 &[0, 1],
4933 vec![
4934 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1)),
4935 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2)),
4936 ],
4937 );
4938
4939 let mut trie = ParallelSparseTrie::from_root(branch, None, true).unwrap();
4941 trie.reveal_nodes(&mut [
4942 ProofTrieNodeV2 { path: leaf_1_path, node: leaf_1, masks: None },
4943 ProofTrieNodeV2 { path: leaf_2_path, node: leaf_2, masks: None },
4944 ])
4945 .unwrap();
4946
4947 trie.upper_subtrie
4950 .nodes
4951 .get_mut(&extension_path)
4952 .unwrap()
4953 .set_state(SparseNodeState::Dirty);
4954 trie.upper_subtrie.nodes.get_mut(&branch_path).unwrap().set_state(SparseNodeState::Dirty);
4955
4956 let leaf_1_subtrie_idx = path_subtrie_index_unchecked(&leaf_1_path);
4958 let leaf_2_subtrie_idx = path_subtrie_index_unchecked(&leaf_2_path);
4959
4960 trie.lower_subtries[leaf_1_subtrie_idx]
4961 .as_revealed_mut()
4962 .unwrap()
4963 .nodes
4964 .get_mut(&leaf_1_path)
4965 .unwrap()
4966 .set_state(SparseNodeState::Dirty);
4967 trie.lower_subtries[leaf_2_subtrie_idx]
4968 .as_revealed_mut()
4969 .unwrap()
4970 .nodes
4971 .get_mut(&leaf_2_path)
4972 .unwrap()
4973 .set_state(SparseNodeState::Dirty);
4974
4975 trie.prefix_set.insert(leaf_1_full_path);
4977 trie.prefix_set.insert(leaf_2_full_path);
4978
4979 let root = trie.root();
4981
4982 let (hash_builder_root, _, _proof_nodes, _, _) = run_hash_builder(
4984 [(leaf_1_full_path, account_1), (leaf_2_full_path, account_2)],
4985 NoopAccountTrieCursor::default(),
4986 Default::default(),
4987 [extension_path, branch_path, leaf_1_full_path, leaf_2_full_path],
4988 );
4989
4990 assert_eq!(root, hash_builder_root);
4992
4993 let leaf_1_subtrie = trie.lower_subtries[leaf_1_subtrie_idx].as_revealed_ref().unwrap();
4995 let leaf_2_subtrie = trie.lower_subtries[leaf_2_subtrie_idx].as_revealed_ref().unwrap();
4996 assert!(trie.upper_subtrie.nodes.get(&extension_path).unwrap().cached_hash().is_some());
4997 assert!(trie.upper_subtrie.nodes.get(&branch_path).unwrap().cached_hash().is_some());
4998 assert!(leaf_1_subtrie.nodes.get(&leaf_1_path).unwrap().cached_hash().is_some());
4999 assert!(leaf_2_subtrie.nodes.get(&leaf_2_path).unwrap().cached_hash().is_some());
5000 }
5001
5002 #[test]
5003 fn sparse_trie_empty_update_one() {
5004 let ctx = ParallelSparseTrieTestContext;
5005
5006 let key = Nibbles::unpack(B256::with_last_byte(42));
5007 let value = || Account::default();
5008 let value_encoded = || {
5009 let mut account_rlp = Vec::new();
5010 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5011 account_rlp
5012 };
5013
5014 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5015 run_hash_builder(
5016 [(key, value())],
5017 NoopAccountTrieCursor::default(),
5018 Default::default(),
5019 [key],
5020 );
5021
5022 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5023 ctx.update_leaves(&mut sparse, [(key, value_encoded())]);
5024 ctx.assert_with_hash_builder(
5025 &mut sparse,
5026 hash_builder_root,
5027 hash_builder_updates,
5028 hash_builder_proof_nodes,
5029 );
5030 }
5031
5032 #[test]
5033 fn sparse_trie_empty_update_multiple_lower_nibbles() {
5034 let ctx = ParallelSparseTrieTestContext;
5035
5036 let paths = (0..=16).map(|b| Nibbles::unpack(B256::with_last_byte(b))).collect::<Vec<_>>();
5037 let value = || Account::default();
5038 let value_encoded = || {
5039 let mut account_rlp = Vec::new();
5040 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5041 account_rlp
5042 };
5043
5044 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5045 run_hash_builder(
5046 paths.iter().copied().zip(core::iter::repeat_with(value)),
5047 NoopAccountTrieCursor::default(),
5048 Default::default(),
5049 paths.clone(),
5050 );
5051
5052 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5053 ctx.update_leaves(
5054 &mut sparse,
5055 paths.into_iter().zip(core::iter::repeat_with(value_encoded)),
5056 );
5057
5058 ctx.assert_with_hash_builder(
5059 &mut sparse,
5060 hash_builder_root,
5061 hash_builder_updates,
5062 hash_builder_proof_nodes,
5063 );
5064 }
5065
5066 #[test]
5067 fn sparse_trie_empty_update_multiple_upper_nibbles() {
5068 let paths = (239..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
5069 let value = || Account::default();
5070 let value_encoded = || {
5071 let mut account_rlp = Vec::new();
5072 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5073 account_rlp
5074 };
5075
5076 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5077 run_hash_builder(
5078 paths.iter().copied().zip(core::iter::repeat_with(value)),
5079 NoopAccountTrieCursor::default(),
5080 Default::default(),
5081 paths.clone(),
5082 );
5083 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5084 for path in &paths {
5085 sparse.update_leaf(*path, value_encoded()).unwrap();
5086 }
5087 let sparse_root = sparse.root();
5088 let sparse_updates = sparse.take_updates();
5089
5090 assert_eq!(sparse_root, hash_builder_root);
5091 assert_eq!(sparse_updates.updated_nodes, hash_builder_updates.account_nodes);
5092 assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
5093 }
5094
5095 #[test]
5096 fn sparse_trie_empty_update_multiple() {
5097 let ctx = ParallelSparseTrieTestContext;
5098
5099 let paths = (0..=255)
5100 .map(|b| {
5101 Nibbles::unpack(if b % 2 == 0 {
5102 B256::repeat_byte(b)
5103 } else {
5104 B256::with_last_byte(b)
5105 })
5106 })
5107 .collect::<Vec<_>>();
5108 let value = || Account::default();
5109 let value_encoded = || {
5110 let mut account_rlp = Vec::new();
5111 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5112 account_rlp
5113 };
5114
5115 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5116 run_hash_builder(
5117 paths.iter().sorted_unstable().copied().zip(core::iter::repeat_with(value)),
5118 NoopAccountTrieCursor::default(),
5119 Default::default(),
5120 paths.clone(),
5121 );
5122
5123 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5124 ctx.update_leaves(
5125 &mut sparse,
5126 paths.iter().copied().zip(core::iter::repeat_with(value_encoded)),
5127 );
5128 ctx.assert_with_hash_builder(
5129 &mut sparse,
5130 hash_builder_root,
5131 hash_builder_updates,
5132 hash_builder_proof_nodes,
5133 );
5134 }
5135
5136 #[test]
5137 fn sparse_trie_empty_update_repeated() {
5138 let ctx = ParallelSparseTrieTestContext;
5139
5140 let paths = (0..=255).map(|b| Nibbles::unpack(B256::repeat_byte(b))).collect::<Vec<_>>();
5141 let old_value = Account { nonce: 1, ..Default::default() };
5142 let old_value_encoded = {
5143 let mut account_rlp = Vec::new();
5144 old_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5145 account_rlp
5146 };
5147 let new_value = Account { nonce: 2, ..Default::default() };
5148 let new_value_encoded = {
5149 let mut account_rlp = Vec::new();
5150 new_value.into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5151 account_rlp
5152 };
5153
5154 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5155 run_hash_builder(
5156 paths.iter().copied().zip(core::iter::repeat_with(|| old_value)),
5157 NoopAccountTrieCursor::default(),
5158 Default::default(),
5159 paths.clone(),
5160 );
5161
5162 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5163 ctx.update_leaves(
5164 &mut sparse,
5165 paths.iter().copied().zip(core::iter::repeat(old_value_encoded)),
5166 );
5167 ctx.assert_with_hash_builder(
5168 &mut sparse,
5169 hash_builder_root,
5170 hash_builder_updates,
5171 hash_builder_proof_nodes,
5172 );
5173
5174 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5175 run_hash_builder(
5176 paths.iter().copied().zip(core::iter::repeat(new_value)),
5177 NoopAccountTrieCursor::default(),
5178 Default::default(),
5179 paths.clone(),
5180 );
5181
5182 ctx.update_leaves(
5183 &mut sparse,
5184 paths.iter().copied().zip(core::iter::repeat(new_value_encoded)),
5185 );
5186 ctx.assert_with_hash_builder(
5187 &mut sparse,
5188 hash_builder_root,
5189 hash_builder_updates,
5190 hash_builder_proof_nodes,
5191 );
5192 }
5193
5194 #[test]
5195 fn sparse_trie_remove_leaf() {
5196 let ctx = ParallelSparseTrieTestContext;
5197 let mut sparse = ParallelSparseTrie::default();
5198
5199 let value = alloy_rlp::encode_fixed_size(&U256::ZERO).to_vec();
5200
5201 ctx.update_leaves(
5202 &mut sparse,
5203 [
5204 (
5205 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1])),
5206 value.clone(),
5207 ),
5208 (
5209 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3])),
5210 value.clone(),
5211 ),
5212 (
5213 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3])),
5214 value.clone(),
5215 ),
5216 (
5217 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2])),
5218 value.clone(),
5219 ),
5220 (
5221 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2])),
5222 value.clone(),
5223 ),
5224 (pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0])), value),
5225 ],
5226 );
5227
5228 pretty_assertions::assert_eq!(
5241 parallel_sparse_trie_nodes(&sparse)
5242 .into_iter()
5243 .map(|(k, v)| (*k, v.clone()))
5244 .collect::<BTreeMap<_, _>>(),
5245 BTreeMap::from_iter([
5246 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5247 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1101.into(), &[])),
5248 (
5249 Nibbles::from_nibbles([0x5, 0x0]),
5250 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
5251 ),
5252 (
5253 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
5254 SparseNode::new_branch(0b1010.into(), &[])
5255 ),
5256 (
5257 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
5258 SparseNode::new_leaf(leaf_key([], 59))
5259 ),
5260 (
5261 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
5262 SparseNode::new_leaf(leaf_key([], 59))
5263 ),
5264 (
5265 Nibbles::from_nibbles([0x5, 0x2]),
5266 SparseNode::new_leaf(leaf_key([0x0, 0x1, 0x3], 62))
5267 ),
5268 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into(), &[])),
5269 (
5270 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5271 SparseNode::new_leaf(leaf_key([0x0, 0x2], 61))
5272 ),
5273 (
5274 Nibbles::from_nibbles([0x5, 0x3, 0x3]),
5275 SparseNode::new_branch(0b0101.into(), &[])
5276 ),
5277 (
5278 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5279 SparseNode::new_leaf(leaf_key([0x2], 60))
5280 ),
5281 (
5282 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5283 SparseNode::new_leaf(leaf_key([0x0], 60))
5284 )
5285 ])
5286 );
5287
5288 sparse
5289 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x2, 0x0, 0x1, 0x3])))
5290 .unwrap();
5291
5292 pretty_assertions::assert_eq!(
5304 parallel_sparse_trie_nodes(&sparse)
5305 .into_iter()
5306 .map(|(k, v)| (*k, v.clone()))
5307 .collect::<BTreeMap<_, _>>(),
5308 BTreeMap::from_iter([
5309 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5310 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into(), &[])),
5311 (
5312 Nibbles::from_nibbles([0x5, 0x0]),
5313 SparseNode::new_ext(Nibbles::from_nibbles([0x2, 0x3]))
5314 ),
5315 (
5316 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3]),
5317 SparseNode::new_branch(0b1010.into(), &[])
5318 ),
5319 (
5320 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1]),
5321 SparseNode::new_leaf(leaf_key([], 59))
5322 ),
5323 (
5324 Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3]),
5325 SparseNode::new_leaf(leaf_key([], 59))
5326 ),
5327 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into(), &[])),
5328 (
5329 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5330 SparseNode::new_leaf(leaf_key([0x0, 0x2], 61))
5331 ),
5332 (
5333 Nibbles::from_nibbles([0x5, 0x3, 0x3]),
5334 SparseNode::new_branch(0b0101.into(), &[])
5335 ),
5336 (
5337 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5338 SparseNode::new_leaf(leaf_key([0x2], 60))
5339 ),
5340 (
5341 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5342 SparseNode::new_leaf(leaf_key([0x0], 60))
5343 )
5344 ])
5345 );
5346
5347 sparse
5348 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x1])))
5349 .unwrap();
5350
5351 pretty_assertions::assert_eq!(
5360 parallel_sparse_trie_nodes(&sparse)
5361 .into_iter()
5362 .map(|(k, v)| (*k, v.clone()))
5363 .collect::<BTreeMap<_, _>>(),
5364 BTreeMap::from_iter([
5365 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5366 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into(), &[])),
5367 (
5368 Nibbles::from_nibbles([0x5, 0x0]),
5369 SparseNode::new_leaf(leaf_key([0x2, 0x3, 0x3], 62))
5370 ),
5371 (Nibbles::from_nibbles([0x5, 0x3]), SparseNode::new_branch(0b1010.into(), &[])),
5372 (
5373 Nibbles::from_nibbles([0x5, 0x3, 0x1]),
5374 SparseNode::new_leaf(leaf_key([0x0, 0x2], 61))
5375 ),
5376 (
5377 Nibbles::from_nibbles([0x5, 0x3, 0x3]),
5378 SparseNode::new_branch(0b0101.into(), &[])
5379 ),
5380 (
5381 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5382 SparseNode::new_leaf(leaf_key([0x2], 60))
5383 ),
5384 (
5385 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5386 SparseNode::new_leaf(leaf_key([0x0], 60))
5387 )
5388 ])
5389 );
5390
5391 sparse
5392 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x1, 0x0, 0x2])))
5393 .unwrap();
5394
5395 pretty_assertions::assert_eq!(
5402 parallel_sparse_trie_nodes(&sparse)
5403 .into_iter()
5404 .map(|(k, v)| (*k, v.clone()))
5405 .collect::<BTreeMap<_, _>>(),
5406 BTreeMap::from_iter([
5407 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5408 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into(), &[])),
5409 (
5410 Nibbles::from_nibbles([0x5, 0x0]),
5411 SparseNode::new_leaf(leaf_key([0x2, 0x3, 0x3], 62))
5412 ),
5413 (
5414 Nibbles::from_nibbles([0x5, 0x3]),
5415 SparseNode::new_ext(Nibbles::from_nibbles([0x3]))
5416 ),
5417 (
5418 Nibbles::from_nibbles([0x5, 0x3, 0x3]),
5419 SparseNode::new_branch(0b0101.into(), &[])
5420 ),
5421 (
5422 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0]),
5423 SparseNode::new_leaf(leaf_key([0x2], 60))
5424 ),
5425 (
5426 Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2]),
5427 SparseNode::new_leaf(leaf_key([0x0], 60))
5428 )
5429 ])
5430 );
5431
5432 sparse
5433 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x2, 0x0])))
5434 .unwrap();
5435
5436 pretty_assertions::assert_eq!(
5441 parallel_sparse_trie_nodes(&sparse)
5442 .into_iter()
5443 .map(|(k, v)| (*k, v.clone()))
5444 .collect::<BTreeMap<_, _>>(),
5445 BTreeMap::from_iter([
5446 (Nibbles::default(), SparseNode::new_ext(Nibbles::from_nibbles([0x5]))),
5447 (Nibbles::from_nibbles([0x5]), SparseNode::new_branch(0b1001.into(), &[])),
5448 (
5449 Nibbles::from_nibbles([0x5, 0x0]),
5450 SparseNode::new_leaf(leaf_key([0x2, 0x3, 0x3], 62))
5451 ),
5452 (
5453 Nibbles::from_nibbles([0x5, 0x3]),
5454 SparseNode::new_leaf(leaf_key([0x3, 0x0, 0x2], 62))
5455 ),
5456 ])
5457 );
5458
5459 sparse
5460 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x0, 0x2, 0x3, 0x3])))
5461 .unwrap();
5462
5463 pretty_assertions::assert_eq!(
5465 parallel_sparse_trie_nodes(&sparse)
5466 .into_iter()
5467 .map(|(k, v)| (*k, v.clone()))
5468 .collect::<BTreeMap<_, _>>(),
5469 BTreeMap::from_iter([(
5470 Nibbles::default(),
5471 SparseNode::new_leaf(pad_nibbles_right(Nibbles::from_nibbles([
5472 0x5, 0x3, 0x3, 0x0, 0x2
5473 ])))
5474 ),])
5475 );
5476
5477 sparse
5478 .remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x3, 0x3, 0x0, 0x2])))
5479 .unwrap();
5480
5481 pretty_assertions::assert_eq!(
5483 parallel_sparse_trie_nodes(&sparse)
5484 .into_iter()
5485 .map(|(k, v)| (*k, v.clone()))
5486 .collect::<BTreeMap<_, _>>(),
5487 BTreeMap::from_iter([(Nibbles::default(), SparseNode::Empty)])
5488 );
5489 }
5490
5491 #[test]
5492 fn sparse_trie_remove_leaf_blinded() {
5493 let leaf = LeafNode::new(
5494 Nibbles::default(),
5495 alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
5496 );
5497 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
5498 Nibbles::default(),
5499 vec![
5500 RlpNode::word_rlp(&B256::repeat_byte(1)),
5501 RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
5502 ],
5503 TrieMask::new(0b11),
5504 None,
5505 ));
5506 let mut sparse = ParallelSparseTrie::from_root(
5507 branch.clone(),
5508 Some(BranchNodeMasks {
5509 hash_mask: TrieMask::new(0b01),
5510 tree_mask: TrieMask::default(),
5511 }),
5512 false,
5513 )
5514 .unwrap();
5515
5516 sparse
5522 .reveal_nodes(&mut [
5523 ProofTrieNodeV2 {
5524 path: Nibbles::default(),
5525 node: branch,
5526 masks: Some(BranchNodeMasks {
5527 hash_mask: TrieMask::default(),
5528 tree_mask: TrieMask::new(0b01),
5529 }),
5530 },
5531 ProofTrieNodeV2 {
5532 path: Nibbles::from_nibbles([0x1]),
5533 node: TrieNodeV2::Leaf(leaf),
5534 masks: None,
5535 },
5536 ])
5537 .unwrap();
5538
5539 assert_matches!(
5541 sparse.remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x0]))).map_err(|e| e.into_kind()),
5542 Err(SparseTrieErrorKind::BlindedNode(path)) if path == Nibbles::from_nibbles([0x0])
5543 );
5544 }
5545
5546 #[test]
5547 fn sparse_trie_remove_leaf_non_existent() {
5548 let leaf = LeafNode::new(
5549 Nibbles::default(),
5550 alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec(),
5551 );
5552 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
5553 Nibbles::default(),
5554 vec![
5555 RlpNode::word_rlp(&B256::repeat_byte(1)),
5556 RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(),
5557 ],
5558 TrieMask::new(0b11),
5559 None,
5560 ));
5561 let mut sparse = ParallelSparseTrie::from_root(
5562 branch.clone(),
5563 Some(BranchNodeMasks {
5564 hash_mask: TrieMask::new(0b01),
5565 tree_mask: TrieMask::default(),
5566 }),
5567 false,
5568 )
5569 .unwrap();
5570
5571 sparse
5577 .reveal_nodes(&mut [
5578 ProofTrieNodeV2 {
5579 path: Nibbles::default(),
5580 node: branch,
5581 masks: Some(BranchNodeMasks {
5582 hash_mask: TrieMask::default(),
5583 tree_mask: TrieMask::new(0b01),
5584 }),
5585 },
5586 ProofTrieNodeV2 {
5587 path: Nibbles::from_nibbles([0x1]),
5588 node: TrieNodeV2::Leaf(leaf),
5589 masks: None,
5590 },
5591 ])
5592 .unwrap();
5593
5594 let sparse_old = sparse.clone();
5596 assert_matches!(
5597 sparse.remove_leaf(&pad_nibbles_right(Nibbles::from_nibbles([0x2]))),
5598 Ok(())
5599 );
5600 assert_eq!(sparse, sparse_old);
5601 }
5602
5603 #[test]
5604 fn sparse_trie_fuzz() {
5605 const KEY_NIBBLES_LEN: usize = 3;
5609
5610 fn test(updates: Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)>) {
5611 {
5612 let mut state = BTreeMap::default();
5613 let provider_factory = create_test_provider_factory();
5614 let mut sparse = ParallelSparseTrie::default().with_updates(true);
5615
5616 for (update, keys_to_delete) in updates {
5617 for (key, account) in update.clone() {
5619 let account = account.into_trie_account(EMPTY_ROOT_HASH);
5620 let mut account_rlp = Vec::new();
5621 account.encode(&mut account_rlp);
5622 sparse.update_leaf(key, account_rlp).unwrap();
5623 }
5624 let mut updated_sparse = sparse.clone();
5628 let sparse_root = updated_sparse.root();
5629 let sparse_updates = updated_sparse.take_updates();
5630
5631 state.extend(update);
5633 let provider = provider_factory.provider().unwrap();
5634 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5635 reth_trie_db::with_adapter!(provider_factory, |A| {
5636 let trie_cursor =
5637 DatabaseTrieCursorFactory::<_, A>::new(provider.tx_ref());
5638 run_hash_builder(
5639 state.clone(),
5640 trie_cursor.account_trie_cursor().unwrap(),
5641 Default::default(),
5642 state.keys().copied(),
5643 )
5644 });
5645
5646 let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
5648
5649 let provider_rw = provider_factory.provider_rw().unwrap();
5651 provider_rw.write_trie_updates(hash_builder_updates).unwrap();
5652 provider_rw.commit().unwrap();
5653
5654 assert_eq!(sparse_root, hash_builder_root);
5656 pretty_assertions::assert_eq!(
5658 BTreeMap::from_iter(sparse_updates.updated_nodes),
5659 BTreeMap::from_iter(hash_builder_account_nodes)
5660 );
5661 assert_eq_parallel_sparse_trie_proof_nodes(
5663 &updated_sparse,
5664 hash_builder_proof_nodes,
5665 );
5666
5667 for key in &keys_to_delete {
5670 state.remove(key).unwrap();
5671 sparse.remove_leaf(key).unwrap();
5672 }
5673
5674 let mut updated_sparse = sparse.clone();
5678 let sparse_root = updated_sparse.root();
5679 let sparse_updates = updated_sparse.take_updates();
5680
5681 let provider = provider_factory.provider().unwrap();
5682 let (hash_builder_root, hash_builder_updates, hash_builder_proof_nodes, _, _) =
5683 reth_trie_db::with_adapter!(provider_factory, |A| {
5684 let trie_cursor =
5685 DatabaseTrieCursorFactory::<_, A>::new(provider.tx_ref());
5686 run_hash_builder(
5687 state.clone(),
5688 trie_cursor.account_trie_cursor().unwrap(),
5689 keys_to_delete
5690 .iter()
5691 .map(|nibbles| B256::from_slice(&nibbles.pack()))
5692 .collect(),
5693 state.keys().copied(),
5694 )
5695 });
5696
5697 let hash_builder_account_nodes = hash_builder_updates.account_nodes.clone();
5699
5700 let provider_rw = provider_factory.provider_rw().unwrap();
5702 provider_rw.write_trie_updates(hash_builder_updates).unwrap();
5703 provider_rw.commit().unwrap();
5704
5705 assert_eq!(sparse_root, hash_builder_root);
5707 pretty_assertions::assert_eq!(
5709 BTreeMap::from_iter(sparse_updates.updated_nodes),
5710 BTreeMap::from_iter(hash_builder_account_nodes)
5711 );
5712 assert_eq_parallel_sparse_trie_proof_nodes(
5714 &updated_sparse,
5715 hash_builder_proof_nodes,
5716 );
5717 }
5718 }
5719 }
5720
5721 fn transform_updates(
5722 updates: Vec<BTreeMap<Nibbles, Account>>,
5723 mut rng: impl rand::Rng,
5724 ) -> Vec<(BTreeMap<Nibbles, Account>, BTreeSet<Nibbles>)> {
5725 let mut keys = BTreeSet::new();
5726 updates
5727 .into_iter()
5728 .map(|update| {
5729 keys.extend(update.keys().copied());
5730
5731 let keys_to_delete_len = update.len() / 2;
5732 let keys_to_delete = (0..keys_to_delete_len)
5733 .map(|_| {
5734 let key =
5735 *rand::seq::IteratorRandom::choose(keys.iter(), &mut rng).unwrap();
5736 keys.take(&key).unwrap()
5737 })
5738 .collect();
5739
5740 (update, keys_to_delete)
5741 })
5742 .collect::<Vec<_>>()
5743 }
5744
5745 proptest!(ProptestConfig::with_cases(10), |(
5746 updates in proptest::collection::vec(
5747 proptest::collection::btree_map(
5748 any_with::<Nibbles>(SizeRange::new(KEY_NIBBLES_LEN..=KEY_NIBBLES_LEN)).prop_map(pad_nibbles_right),
5749 arb::<Account>(),
5750 1..50,
5751 ),
5752 1..50,
5753 ).prop_perturb(transform_updates)
5754 )| {
5755 test(updates)
5756 });
5757 }
5758
5759 #[test]
5760 fn sparse_trie_two_leaves_at_lower_roots() {
5761 let mut trie = ParallelSparseTrie::default().with_updates(true);
5762 let key_50 = Nibbles::unpack(hex!(
5763 "0x5000000000000000000000000000000000000000000000000000000000000000"
5764 ));
5765 let key_51 = Nibbles::unpack(hex!(
5766 "0x5100000000000000000000000000000000000000000000000000000000000000"
5767 ));
5768
5769 let account = Account::default().into_trie_account(EMPTY_ROOT_HASH);
5770 let mut account_rlp = Vec::new();
5771 account.encode(&mut account_rlp);
5772
5773 trie.update_leaf(key_50, account_rlp.clone()).unwrap();
5775 trie.root();
5776
5777 trie.update_leaf(key_51, account_rlp.clone()).unwrap();
5779
5780 let expected_root =
5781 hex!("0xdaf0ef9f91a2f179bb74501209effdb5301db1697bcab041eca2234b126e25de");
5782 let root = trie.root();
5783 assert_eq!(root, expected_root);
5784 assert_eq!(SparseTrieUpdates::default(), trie.take_updates());
5785 }
5786
5787 #[test]
5799 fn sparse_trie_reveal_node_1() {
5800 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00]));
5801 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01]));
5802 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x02]));
5803 let value = || Account::default();
5804 let value_encoded = || {
5805 let mut account_rlp = Vec::new();
5806 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
5807 account_rlp
5808 };
5809
5810 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5812 run_hash_builder(
5813 [(key1(), value()), (key3(), value())],
5814 NoopAccountTrieCursor::default(),
5815 Default::default(),
5816 [Nibbles::default()],
5817 );
5818 let masks = match (
5819 branch_node_hash_masks.get(&Nibbles::default()).copied(),
5820 branch_node_tree_masks.get(&Nibbles::default()).copied(),
5821 ) {
5822 (Some(h), Some(t)) => Some(BranchNodeMasks { hash_mask: h, tree_mask: t }),
5823 (Some(h), None) => {
5824 Some(BranchNodeMasks { hash_mask: h, tree_mask: TrieMask::default() })
5825 }
5826 (None, Some(t)) => {
5827 Some(BranchNodeMasks { hash_mask: TrieMask::default(), tree_mask: t })
5828 }
5829 (None, None) => None,
5830 };
5831 let mut sparse = ParallelSparseTrie::from_root(
5832 TrieNodeV2::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
5833 masks,
5834 false,
5835 )
5836 .unwrap();
5837
5838 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5840 run_hash_builder(
5841 [(key1(), value()), (key3(), value())],
5842 NoopAccountTrieCursor::default(),
5843 Default::default(),
5844 [key1()],
5845 );
5846 let mut revealed_nodes: Vec<ProofTrieNodeV2> = hash_builder_proof_nodes
5847 .nodes_sorted()
5848 .into_iter()
5849 .map(|(path, node)| {
5850 let hash_mask = branch_node_hash_masks.get(&path).copied();
5851 let tree_mask = branch_node_tree_masks.get(&path).copied();
5852 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
5853 ProofTrieNodeV2 { path, node: TrieNodeV2::decode(&mut &node[..]).unwrap(), masks }
5854 })
5855 .collect();
5856 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
5857
5858 assert_matches!(
5860 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5861 Some(&SparseNode::Branch { state_mask, state: SparseNodeState::Dirty, .. }) if state_mask == TrieMask::new(0b101)
5862 );
5863
5864 sparse.update_leaf(key2(), value_encoded()).unwrap();
5866
5867 assert_matches!(
5869 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5870 Some(&SparseNode::Branch { state_mask, state: SparseNodeState::Dirty, .. }) if state_mask == TrieMask::new(0b111)
5871 );
5872
5873 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5875 run_hash_builder(
5876 [(key1(), value()), (key3(), value())],
5877 NoopAccountTrieCursor::default(),
5878 Default::default(),
5879 [key3()],
5880 );
5881 let mut revealed_nodes: Vec<ProofTrieNodeV2> = hash_builder_proof_nodes
5882 .nodes_sorted()
5883 .into_iter()
5884 .map(|(path, node)| {
5885 let hash_mask = branch_node_hash_masks.get(&path).copied();
5886 let tree_mask = branch_node_tree_masks.get(&path).copied();
5887 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
5888 ProofTrieNodeV2 { path, node: TrieNodeV2::decode(&mut &node[..]).unwrap(), masks }
5889 })
5890 .collect();
5891 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
5892
5893 assert_matches!(
5895 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5896 Some(&SparseNode::Branch { state_mask, state: SparseNodeState::Dirty, .. }) if state_mask == TrieMask::new(0b111)
5897 );
5898
5899 let (_, _, hash_builder_proof_nodes, _, _) = run_hash_builder(
5902 [(key1(), value()), (key2(), value()), (key3(), value())],
5903 NoopAccountTrieCursor::default(),
5904 Default::default(),
5905 [key1(), key2(), key3()],
5906 );
5907
5908 assert_eq_parallel_sparse_trie_proof_nodes(&sparse, hash_builder_proof_nodes);
5909 }
5910
5911 #[test]
5922 fn sparse_trie_reveal_node_2() {
5923 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x00]));
5924 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x01]));
5925 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x02]));
5926 let value = || Account::default();
5927
5928 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5930 run_hash_builder(
5931 [(key1(), value()), (key2(), value()), (key3(), value())],
5932 NoopAccountTrieCursor::default(),
5933 Default::default(),
5934 [Nibbles::default()],
5935 );
5936 let masks = match (
5937 branch_node_hash_masks.get(&Nibbles::default()).copied(),
5938 branch_node_tree_masks.get(&Nibbles::default()).copied(),
5939 ) {
5940 (Some(h), Some(t)) => Some(BranchNodeMasks { hash_mask: h, tree_mask: t }),
5941 (Some(h), None) => {
5942 Some(BranchNodeMasks { hash_mask: h, tree_mask: TrieMask::default() })
5943 }
5944 (None, Some(t)) => {
5945 Some(BranchNodeMasks { hash_mask: TrieMask::default(), tree_mask: t })
5946 }
5947 (None, None) => None,
5948 };
5949 let mut sparse = ParallelSparseTrie::from_root(
5950 TrieNodeV2::decode(&mut &hash_builder_proof_nodes.nodes_sorted()[0].1[..]).unwrap(),
5951 masks,
5952 false,
5953 )
5954 .unwrap();
5955
5956 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5959 run_hash_builder(
5960 [(key1(), value()), (key2(), value()), (key3(), value())],
5961 NoopAccountTrieCursor::default(),
5962 Default::default(),
5963 [key1(), Nibbles::from_nibbles_unchecked([0x01])],
5964 );
5965 let mut revealed_nodes: Vec<ProofTrieNodeV2> = hash_builder_proof_nodes
5966 .nodes_sorted()
5967 .into_iter()
5968 .map(|(path, node)| {
5969 let hash_mask = branch_node_hash_masks.get(&path).copied();
5970 let tree_mask = branch_node_tree_masks.get(&path).copied();
5971 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
5972 ProofTrieNodeV2 { path, node: TrieNodeV2::decode(&mut &node[..]).unwrap(), masks }
5973 })
5974 .collect();
5975 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
5976
5977 assert_matches!(
5979 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5980 Some(&SparseNode::Branch { state_mask, state: SparseNodeState::Dirty, .. }) if state_mask == TrieMask::new(0b11)
5981 );
5982
5983 sparse.remove_leaf(&key1()).unwrap();
5985
5986 assert_eq!(
5988 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
5989 Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
5990 );
5991
5992 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
5994 run_hash_builder(
5995 [(key1(), value()), (key2(), value()), (key3(), value())],
5996 NoopAccountTrieCursor::default(),
5997 Default::default(),
5998 [key2()],
5999 );
6000 let mut revealed_nodes: Vec<ProofTrieNodeV2> = hash_builder_proof_nodes
6001 .nodes_sorted()
6002 .into_iter()
6003 .map(|(path, node)| {
6004 let hash_mask = branch_node_hash_masks.get(&path).copied();
6005 let tree_mask = branch_node_tree_masks.get(&path).copied();
6006 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6007 ProofTrieNodeV2 { path, node: TrieNodeV2::decode(&mut &node[..]).unwrap(), masks }
6008 })
6009 .collect();
6010 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6011
6012 assert_eq!(
6014 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6015 Some(&SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x01])))
6016 );
6017 }
6018
6019 #[test]
6028 fn sparse_trie_reveal_node_3() {
6029 let key1 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x01]));
6030 let key2 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x00, 0x02]));
6031 let key3 = || pad_nibbles_right(Nibbles::from_nibbles_unchecked([0x01, 0x00]));
6032 let value = || Account::default();
6033 let value_encoded = || {
6034 let mut account_rlp = Vec::new();
6035 value().into_trie_account(EMPTY_ROOT_HASH).encode(&mut account_rlp);
6036 account_rlp
6037 };
6038
6039 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6041 run_hash_builder(
6042 [(key1(), value()), (key2(), value())],
6043 NoopAccountTrieCursor::default(),
6044 Default::default(),
6045 [Nibbles::default()],
6046 );
6047
6048 let mut nodes = Vec::new();
6049
6050 for (path, node) in hash_builder_proof_nodes.nodes_sorted() {
6051 let hash_mask = branch_node_hash_masks.get(&path).copied();
6052 let tree_mask = branch_node_tree_masks.get(&path).copied();
6053 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6054 nodes.push((path, TrieNode::decode(&mut &node[..]).unwrap(), masks));
6055 }
6056
6057 nodes.sort_unstable_by(|a, b| reth_trie_common::depth_first_cmp(&a.0, &b.0));
6058
6059 let nodes = ProofTrieNodeV2::from_sorted_trie_nodes(nodes);
6060 let mut sparse =
6061 ParallelSparseTrie::from_root(nodes[0].node.clone(), nodes[0].masks, false).unwrap();
6062
6063 assert_matches!(
6065 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6066 Some(SparseNode::Extension { key, state: SparseNodeState::Dirty }) if *key == Nibbles::from_nibbles([0x00])
6067 );
6068
6069 sparse.update_leaf(key3(), value_encoded()).unwrap();
6071
6072 assert_eq!(
6074 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6075 Some(&SparseNode::new_branch(TrieMask::new(0b11), &[]))
6076 );
6077
6078 let (_, _, hash_builder_proof_nodes, branch_node_hash_masks, branch_node_tree_masks) =
6080 run_hash_builder(
6081 [(key1(), value()), (key2(), value())],
6082 NoopAccountTrieCursor::default(),
6083 Default::default(),
6084 [key1()],
6085 );
6086 let mut revealed_nodes: Vec<ProofTrieNodeV2> = hash_builder_proof_nodes
6087 .nodes_sorted()
6088 .into_iter()
6089 .map(|(path, node)| {
6090 let hash_mask = branch_node_hash_masks.get(&path).copied();
6091 let tree_mask = branch_node_tree_masks.get(&path).copied();
6092 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
6093 ProofTrieNodeV2 { path, node: TrieNodeV2::decode(&mut &node[..]).unwrap(), masks }
6094 })
6095 .collect();
6096 sparse.reveal_nodes(&mut revealed_nodes).unwrap();
6097
6098 assert_eq!(
6100 sparse.upper_subtrie.nodes.get(&Nibbles::default()),
6101 Some(&SparseNode::new_branch(TrieMask::new(0b11), &[]))
6102 );
6103 }
6104
6105 #[test]
6106 fn test_update_leaf_cross_level() {
6107 let ctx = ParallelSparseTrieTestContext;
6108 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6109
6110 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x3, 0x4, 0x5], 1);
6132 trie.update_leaf(leaf1_path, value1.clone()).unwrap();
6133
6134 ctx.assert_upper_subtrie(&trie)
6136 .has_leaf(
6137 &Nibbles::default(),
6138 &pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x3, 0x4, 0x5])),
6139 )
6140 .has_value(&leaf1_path, &value1);
6141
6142 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
6144 trie.update_leaf(leaf2_path, value2.clone()).unwrap();
6145
6146 ctx.assert_upper_subtrie(&trie)
6148 .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
6149 .has_no_value(&leaf1_path)
6150 .has_no_value(&leaf2_path);
6151
6152 let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x4, 0x5], 3);
6154 trie.update_leaf(leaf3_path, value3.clone()).unwrap();
6155
6156 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6158 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6159 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &leaf_key([0x4], 61))
6160 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &leaf_key([0x5], 61))
6161 .has_value(&leaf2_path, &value2)
6162 .has_value(&leaf3_path, &value3);
6163
6164 let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x3, 0x3, 0x4], 4);
6166 trie.update_leaf(leaf4_path, value4.clone()).unwrap();
6167
6168 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x3]))
6170 .has_value(&leaf1_path, &value1)
6171 .has_value(&leaf4_path, &value4);
6172
6173 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6175 .has_value(&leaf2_path, &value2)
6176 .has_value(&leaf3_path, &value3);
6177
6178 ctx.assert_upper_subtrie(&trie)
6180 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1]))
6181 .has_branch(&Nibbles::from_nibbles([0x1]), &[0x2, 0x3])
6182 .has_no_value(&leaf1_path)
6183 .has_no_value(&leaf2_path)
6184 .has_no_value(&leaf3_path)
6185 .has_no_value(&leaf4_path);
6186 }
6187
6188 #[test]
6189 fn test_update_leaf_split_at_level_boundary() {
6190 let ctx = ParallelSparseTrieTestContext;
6191 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6192
6193 let (first_leaf_path, first_value) = ctx.create_test_leaf([0x1, 0x2, 0x2, 0x4], 1);
6208
6209 trie.update_leaf(first_leaf_path, first_value.clone()).unwrap();
6210
6211 ctx.assert_upper_subtrie(&trie)
6213 .has_leaf(
6214 &Nibbles::default(),
6215 &pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x2, 0x4])),
6216 )
6217 .has_value(&first_leaf_path, &first_value);
6218
6219 let (second_leaf_path, second_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 2);
6221
6222 trie.update_leaf(second_leaf_path, second_value.clone()).unwrap();
6223
6224 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6226 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x2, 0x3])
6227 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x2]), &leaf_key([0x4], 61))
6228 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &leaf_key([0x4], 61))
6229 .has_value(&first_leaf_path, &first_value)
6230 .has_value(&second_leaf_path, &second_value);
6231
6232 ctx.assert_upper_subtrie(&trie)
6234 .has_no_value(&first_leaf_path)
6235 .has_no_value(&second_leaf_path);
6236 }
6237
6238 #[test]
6239 fn test_update_subtrie_with_multiple_leaves() {
6240 let ctx = ParallelSparseTrieTestContext;
6241 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6242
6243 let leaves = ctx.create_test_leaves(&[
6257 &[0x1, 0x2, 0x3, 0x4],
6258 &[0x1, 0x2, 0x3, 0x5],
6259 &[0x1, 0x2, 0x4, 0x6],
6260 &[0x1, 0x2, 0x4, 0x7],
6261 ]);
6262
6263 ctx.update_leaves(&mut trie, leaves.clone());
6265
6266 ctx.assert_upper_subtrie(&trie)
6268 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6269
6270 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6272 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6273 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6274 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &[0x6, 0x7])
6275 .has_value(&leaves[0].0, &leaves[0].1)
6276 .has_value(&leaves[1].0, &leaves[1].1)
6277 .has_value(&leaves[2].0, &leaves[2].1)
6278 .has_value(&leaves[3].0, &leaves[3].1);
6279
6280 let updated_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
6282 let (_, updated_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 100);
6283
6284 trie.update_leaf(updated_path, updated_value.clone()).unwrap();
6285
6286 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6289 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6290 .has_value(&updated_path, &updated_value)
6291 .has_value(&leaves[1].0, &leaves[1].1)
6292 .has_value(&leaves[2].0, &leaves[2].1)
6293 .has_value(&leaves[3].0, &leaves[3].1);
6294
6295 let (new_leaf_path, new_leaf_value) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 200);
6297
6298 trie.update_leaf(new_leaf_path, new_leaf_value.clone()).unwrap();
6299
6300 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6302 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6])
6303 .has_value(&new_leaf_path, &new_leaf_value);
6304 }
6305
6306 #[test]
6307 fn test_update_subtrie_extension_node_subtrie() {
6308 let ctx = ParallelSparseTrieTestContext;
6309 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6310
6311 let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x3, 0x5]]);
6320
6321 ctx.update_leaves(&mut trie, leaves.clone());
6323
6324 ctx.assert_upper_subtrie(&trie)
6326 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6327
6328 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6330 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6331 .has_value(&leaves[0].0, &leaves[0].1)
6332 .has_value(&leaves[1].0, &leaves[1].1);
6333 }
6334
6335 #[test]
6336 fn update_subtrie_extension_node_cross_level() {
6337 let ctx = ParallelSparseTrieTestContext;
6338 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6339
6340 let leaves = ctx.create_test_leaves(&[&[0x1, 0x2, 0x3, 0x4], &[0x1, 0x2, 0x4, 0x5]]);
6350
6351 ctx.update_leaves(&mut trie, leaves.clone());
6353
6354 ctx.assert_upper_subtrie(&trie)
6356 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6357
6358 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6360 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6361 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &leaf_key([0x4], 61))
6362 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &leaf_key([0x5], 61))
6363 .has_value(&leaves[0].0, &leaves[0].1)
6364 .has_value(&leaves[1].0, &leaves[1].1);
6365 }
6366
6367 #[test]
6368 fn test_update_single_nibble_paths() {
6369 let ctx = ParallelSparseTrieTestContext;
6370 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6371
6372 let (leaf1_path, value1) = ctx.create_test_leaf([0x0], 1);
6384 let (leaf2_path, value2) = ctx.create_test_leaf([0x1], 2);
6385 let (leaf3_path, value3) = ctx.create_test_leaf([0x2], 3);
6386 let (leaf4_path, value4) = ctx.create_test_leaf([0x3], 4);
6387
6388 ctx.update_leaves(
6389 &mut trie,
6390 [
6391 (leaf1_path, value1.clone()),
6392 (leaf2_path, value2.clone()),
6393 (leaf3_path, value3.clone()),
6394 (leaf4_path, value4.clone()),
6395 ],
6396 );
6397
6398 ctx.assert_upper_subtrie(&trie)
6400 .has_branch(&Nibbles::default(), &[0x0, 0x1, 0x2, 0x3])
6401 .has_leaf(&Nibbles::from_nibbles([0x0]), &leaf_key([], 63))
6402 .has_leaf(&Nibbles::from_nibbles([0x1]), &leaf_key([], 63))
6403 .has_leaf(&Nibbles::from_nibbles([0x2]), &leaf_key([], 63))
6404 .has_leaf(&Nibbles::from_nibbles([0x3]), &leaf_key([], 63))
6405 .has_value(&leaf1_path, &value1)
6406 .has_value(&leaf2_path, &value2)
6407 .has_value(&leaf3_path, &value3)
6408 .has_value(&leaf4_path, &value4);
6409 }
6410
6411 #[test]
6412 fn test_update_deep_extension_chain() {
6413 let ctx = ParallelSparseTrieTestContext;
6414 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6415
6416 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0], 1);
6430 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1], 2);
6431
6432 ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
6433
6434 ctx.assert_upper_subtrie(&trie).has_extension(
6436 &Nibbles::default(),
6437 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
6438 );
6439
6440 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x1]))
6442 .has_branch(&Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1]), &[0x0, 0x1])
6443 .has_leaf(
6444 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0]),
6445 &leaf_key([], 57),
6446 )
6447 .has_leaf(
6448 &Nibbles::from_nibbles([0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1]),
6449 &leaf_key([], 57),
6450 )
6451 .has_value(&leaf1_path, &value1)
6452 .has_value(&leaf2_path, &value2);
6453 }
6454
6455 #[test]
6456 fn test_update_branch_with_all_nibbles() {
6457 let ctx = ParallelSparseTrieTestContext;
6458 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6459
6460 let mut leaves = Vec::new();
6477 for nibble in 0x0..=0xF {
6478 let (path, value) = ctx.create_test_leaf([0xA, 0x0, nibble], nibble as u64 + 1);
6479 leaves.push((path, value));
6480 }
6481
6482 ctx.update_leaves(&mut trie, leaves.iter().cloned());
6484
6485 ctx.assert_upper_subtrie(&trie)
6487 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0x0]));
6488
6489 let mut subtrie_assert =
6491 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0x0])).has_branch(
6492 &Nibbles::from_nibbles([0xA, 0x0]),
6493 &[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
6494 );
6495
6496 for (i, (path, value)) in leaves.iter().enumerate() {
6498 subtrie_assert = subtrie_assert
6499 .has_leaf(&Nibbles::from_nibbles([0xA, 0x0, i as u8]), &leaf_key([], 61))
6500 .has_value(path, value);
6501 }
6502 }
6503
6504 #[test]
6505 fn test_update_creates_multiple_subtries() {
6506 let ctx = ParallelSparseTrieTestContext;
6507 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6508
6509 let leaves = [
6525 ctx.create_test_leaf([0x0, 0x0, 0x1, 0x2], 1),
6526 ctx.create_test_leaf([0x0, 0x1, 0x3, 0x4], 2),
6527 ctx.create_test_leaf([0x0, 0x2, 0x5, 0x6], 3),
6528 ctx.create_test_leaf([0x0, 0x3, 0x7, 0x8], 4),
6529 ];
6530
6531 ctx.update_leaves(&mut trie, leaves.iter().cloned());
6533
6534 ctx.assert_upper_subtrie(&trie)
6536 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x0]))
6537 .has_branch(&Nibbles::from_nibbles([0x0]), &[0x0, 0x1, 0x2, 0x3]);
6538
6539 for (i, (leaf_path, leaf_value)) in leaves.iter().enumerate() {
6541 let subtrie_path = Nibbles::from_nibbles([0x0, i as u8]);
6542 let full_path: [u8; 4] = match i {
6543 0 => [0x0, 0x0, 0x1, 0x2],
6544 1 => [0x0, 0x1, 0x3, 0x4],
6545 2 => [0x0, 0x2, 0x5, 0x6],
6546 3 => [0x0, 0x3, 0x7, 0x8],
6547 _ => unreachable!(),
6548 };
6549 ctx.assert_subtrie(&trie, subtrie_path)
6550 .has_leaf(&subtrie_path, &leaf_key(&full_path[2..], 62))
6551 .has_value(leaf_path, leaf_value);
6552 }
6553 }
6554
6555 #[test]
6556 fn test_update_extension_to_branch_transformation() {
6557 let ctx = ParallelSparseTrieTestContext;
6558 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6559
6560 let (leaf1_path, value1) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x1], 1);
6576 let (leaf2_path, value2) = ctx.create_test_leaf([0xF, 0xF, 0x0, 0x2], 2);
6577 let (leaf3_path, value3) = ctx.create_test_leaf([0xF, 0x0, 0x0, 0x3], 3);
6578
6579 ctx.update_leaves(&mut trie, [(leaf1_path, value1.clone()), (leaf2_path, value2.clone())]);
6580
6581 ctx.assert_upper_subtrie(&trie)
6583 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF, 0xF, 0x0]));
6584
6585 ctx.update_leaves(&mut trie, [(leaf3_path, value3.clone())]);
6587
6588 ctx.assert_upper_subtrie(&trie)
6590 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xF]))
6591 .has_branch(&Nibbles::from_nibbles([0xF]), &[0x0, 0xF]);
6592
6593 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
6595 .has_branch(&Nibbles::from_nibbles([0xF, 0xF, 0x0]), &[0x1, 0x2])
6596 .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x1]), &leaf_key([], 60))
6597 .has_leaf(&Nibbles::from_nibbles([0xF, 0xF, 0x0, 0x2]), &leaf_key([], 60))
6598 .has_value(&leaf1_path, &value1)
6599 .has_value(&leaf2_path, &value2);
6600
6601 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0x0]))
6602 .has_leaf(&Nibbles::from_nibbles([0xF, 0x0]), &leaf_key([0x0, 0x3], 62))
6603 .has_value(&leaf3_path, &value3);
6604 }
6605
6606 #[test]
6607 fn test_update_long_shared_prefix_at_boundary() {
6608 let ctx = ParallelSparseTrieTestContext;
6609 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6610
6611 let (leaf1_path, value1) = ctx.create_test_leaf([0xA, 0xB, 0xC, 0xD, 0xE, 0xF], 1);
6625 let (leaf2_path, value2) = ctx.create_test_leaf([0xA, 0xB, 0xD, 0xE, 0xF, 0x0], 2);
6626
6627 trie.update_leaf(leaf1_path, value1.clone()).unwrap();
6628 trie.update_leaf(leaf2_path, value2.clone()).unwrap();
6629
6630 ctx.assert_upper_subtrie(&trie)
6632 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0xA, 0xB]));
6633
6634 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xA, 0xB]))
6636 .has_branch(&Nibbles::from_nibbles([0xA, 0xB]), &[0xC, 0xD])
6637 .has_leaf(&Nibbles::from_nibbles([0xA, 0xB, 0xC]), &leaf_key([0xD, 0xE, 0xF], 61))
6638 .has_leaf(&Nibbles::from_nibbles([0xA, 0xB, 0xD]), &leaf_key([0xE, 0xF, 0x0], 61))
6639 .has_value(&leaf1_path, &value1)
6640 .has_value(&leaf2_path, &value2);
6641 }
6642
6643 #[test]
6644 fn test_update_branch_to_extension_collapse() {
6645 let ctx = ParallelSparseTrieTestContext;
6646 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6647
6648 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
6674 let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
6675 let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
6676
6677 trie.update_leaf(leaf1_path, value1).unwrap();
6678 trie.update_leaf(leaf2_path, value2).unwrap();
6679 trie.update_leaf(leaf3_path, value3).unwrap();
6680
6681 ctx.assert_upper_subtrie(&trie).has_branch(&Nibbles::default(), &[0x1, 0x2]);
6683
6684 let (new_leaf1_path, new_value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 10);
6687 let (new_leaf2_path, new_value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 11);
6688 let (new_leaf3_path, new_value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x6], 12);
6689
6690 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6692 trie.update_leaf(new_leaf1_path, new_value1.clone()).unwrap();
6693 trie.update_leaf(new_leaf2_path, new_value2.clone()).unwrap();
6694 trie.update_leaf(new_leaf3_path, new_value3.clone()).unwrap();
6695
6696 ctx.assert_upper_subtrie(&trie)
6698 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6699
6700 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
6702
6703 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6705 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5, 0x6]) .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &leaf_key([], 60))
6707 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &leaf_key([], 60))
6708 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x6]), &leaf_key([], 60))
6709 .has_value(&new_leaf1_path, &new_value1)
6710 .has_value(&new_leaf2_path, &new_value2)
6711 .has_value(&new_leaf3_path, &new_value3);
6712 }
6713
6714 #[test]
6715 fn test_update_shared_prefix_patterns() {
6716 let ctx = ParallelSparseTrieTestContext;
6717 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6718
6719 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4], 1);
6735 let (leaf2_path, value2) = ctx.create_test_leaf([0x2, 0x3, 0x4, 0x5], 2);
6736 let (leaf3_path, value3) = ctx.create_test_leaf([0x2, 0x3, 0x5, 0x6], 3);
6737
6738 trie.update_leaf(leaf1_path, value1).unwrap();
6739 trie.update_leaf(leaf2_path, value2.clone()).unwrap();
6740 trie.update_leaf(leaf3_path, value3.clone()).unwrap();
6741
6742 ctx.assert_upper_subtrie(&trie)
6744 .has_branch(&Nibbles::default(), &[0x1, 0x2])
6745 .has_leaf(&Nibbles::from_nibbles([0x1]), &leaf_key([0x2, 0x3, 0x4], 63))
6746 .has_extension(&Nibbles::from_nibbles([0x2]), &Nibbles::from_nibbles([0x3]));
6747
6748 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x2, 0x3]))
6750 .has_branch(&Nibbles::from_nibbles([0x2, 0x3]), &[0x4, 0x5])
6751 .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x4]), &leaf_key([0x5], 61))
6752 .has_leaf(&Nibbles::from_nibbles([0x2, 0x3, 0x5]), &leaf_key([0x6], 61))
6753 .has_value(&leaf2_path, &value2)
6754 .has_value(&leaf3_path, &value3);
6755 }
6756
6757 #[test]
6758 fn test_progressive_branch_creation() {
6759 let ctx = ParallelSparseTrieTestContext;
6760 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6761
6762 let (leaf1_path, value1) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x5], 1);
6798 trie.update_leaf(leaf1_path, value1.clone()).unwrap();
6799
6800 ctx.assert_upper_subtrie(&trie)
6802 .has_leaf(
6803 &Nibbles::default(),
6804 &pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5])),
6805 )
6806 .has_value(&leaf1_path, &value1);
6807
6808 let (leaf2_path, value2) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x4, 0x6], 2);
6810 trie.update_leaf(leaf2_path, value2.clone()).unwrap();
6811
6812 ctx.assert_upper_subtrie(&trie)
6814 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
6815
6816 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3, 0x4]);
6818
6819 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6820 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6821 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5]), &leaf_key([], 59))
6822 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x6]), &leaf_key([], 59))
6823 .has_value(&leaf1_path, &value1)
6824 .has_value(&leaf2_path, &value2);
6825
6826 let (leaf3_path, value3) = ctx.create_test_leaf([0x1, 0x2, 0x3, 0x5], 3);
6828 trie.update_leaf(leaf3_path, value3.clone()).unwrap();
6829
6830 ctx.assert_upper_subtrie(&trie)
6832 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2, 0x3]));
6833
6834 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2, 0x3]);
6836
6837 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6838 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6839 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6840 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x5]), &leaf_key([], 60))
6841 .has_value(&leaf1_path, &value1)
6842 .has_value(&leaf2_path, &value2)
6843 .has_value(&leaf3_path, &value3);
6844
6845 let (leaf4_path, value4) = ctx.create_test_leaf([0x1, 0x2, 0x4], 4);
6847 trie.update_leaf(leaf4_path, value4.clone()).unwrap();
6848
6849 ctx.assert_upper_subtrie(&trie)
6851 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles([0x1, 0x2]));
6852
6853 ctx.assert_subtrie_path(&trie, [0x1, 0x2], [0x1, 0x2]);
6855
6856 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0x1, 0x2]))
6858 .has_branch(&Nibbles::from_nibbles([0x1, 0x2]), &[0x3, 0x4])
6859 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3]), &[0x4, 0x5])
6860 .has_branch(&Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]), &[0x5, 0x6])
6861 .has_leaf(&Nibbles::from_nibbles([0x1, 0x2, 0x4]), &leaf_key([], 61))
6862 .has_value(&leaf1_path, &value1)
6863 .has_value(&leaf2_path, &value2)
6864 .has_value(&leaf3_path, &value3)
6865 .has_value(&leaf4_path, &value4);
6866 }
6867
6868 #[test]
6869 fn test_update_max_depth_paths() {
6870 let ctx = ParallelSparseTrieTestContext;
6871 let mut trie = ParallelSparseTrie::from_root(TrieNodeV2::EmptyRoot, None, true).unwrap();
6872
6873 let mut path1_nibbles = vec![0xF; 63];
6885 path1_nibbles.push(0x0);
6886 let mut path2_nibbles = vec![0xF; 63];
6887 path2_nibbles.push(0x1);
6888
6889 let (leaf1_path, value1) = ctx.create_test_leaf(&path1_nibbles, 1);
6890 let (leaf2_path, value2) = ctx.create_test_leaf(&path2_nibbles, 2);
6891
6892 trie.update_leaf(leaf1_path, value1.clone()).unwrap();
6893 trie.update_leaf(leaf2_path, value2.clone()).unwrap();
6894
6895 let extension_key = vec![0xF; 63];
6897 ctx.assert_upper_subtrie(&trie)
6898 .has_extension(&Nibbles::default(), &Nibbles::from_nibbles(&extension_key));
6899
6900 ctx.assert_subtrie(&trie, Nibbles::from_nibbles([0xF, 0xF]))
6902 .has_branch(&Nibbles::from_nibbles(&path1_nibbles[..63]), &[0x0, 0x1])
6903 .has_value(&leaf1_path, &value1)
6904 .has_value(&leaf2_path, &value2);
6905 }
6906
6907 #[test]
6908 fn test_hoodie_block_1_data() {
6909 let root_branch_stack = vec![
6911 hex!("a0550b6aba4dd4582a2434d2cbdad8d3007d09f622d7a6e6eaa7a49385823c2fa2"),
6912 hex!("a04788a4975a9e1efd29b834fd80fdfe8a57cc1b1c5ace6d30ce5a36a15e0092b3"),
6913 hex!("a093aeccf87da304e6f7d09edc5d7bd3a552808866d2149dd0940507a8f9bfa910"),
6914 hex!("a08b5b423ba68d0dec2eca1f408076f9170678505eb4a5db2abbbd83bb37666949"),
6915 hex!("a08592f62216af4218098a78acad7cf472a727fb55e6c27d3cfdf2774d4518eb83"),
6916 hex!("a0ef02aeee845cb64c11f85edc1a3094227c26445952554b8a9248915d80c746c3"),
6917 hex!("a0df2529ee3a1ce4df5a758cf17e6a86d0fb5ea22ab7071cf60af6412e9b0a428a"),
6918 hex!("a0acaa1092db69cd5a63676685827b3484c4b80dc1d3361f6073bbb9240101e144"),
6919 hex!("a09c3f2bb2a729d71f246a833353ade65667716bb330e0127a3299a42d11200f93"),
6920 hex!("a0ce978470f4c0b1f8069570563a14d2b79d709add2db4bf22dd9b6aed3271c566"),
6921 hex!("a095f783cd1d464a60e3c8adcadc28c6eb9fec7306664df39553be41dccc909606"),
6922 hex!("a0a9083f5fb914b255e1feb5d951a4dfddacf3c8003ef1d1ec6a13bb6ba5b2ac62"),
6923 hex!("a0fec113d537d8577cd361e0cabf5e95ef58f1cc34318292fdecce9fae57c3e094"),
6924 hex!("a08b7465f5fe8b3e3c0d087cb7521310d4065ef2a0ee43bf73f68dee8a5742b3dd"),
6925 hex!("a0c589aa1ae3d5fd87d8640957f7d5184a4ac06f393b453a8e8ed7e8fba0d385c8"),
6926 hex!("a0b516d6f3352f87beab4ed6e7322f191fc7a147686500ef4de7dd290ad784ef51"),
6927 ];
6928
6929 let root_branch_rlp_stack: Vec<RlpNode> = root_branch_stack
6930 .iter()
6931 .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
6932 .collect();
6933
6934 let root_branch_node = BranchNodeV2::new(
6935 Default::default(),
6936 root_branch_rlp_stack,
6937 TrieMask::new(0b1111111111111111), None,
6939 );
6940
6941 let root_branch_masks = Some(BranchNodeMasks {
6942 hash_mask: TrieMask::new(0b1111111111111111),
6943 tree_mask: TrieMask::new(0b1111111111111111),
6944 });
6945
6946 let mut trie = ParallelSparseTrie::from_root(
6947 TrieNodeV2::Branch(root_branch_node),
6948 root_branch_masks,
6949 true,
6950 )
6951 .unwrap();
6952
6953 let branch_0x3_stack = vec![
6955 hex!("a09da7d9755fe0c558b3c3de9fdcdf9f28ae641f38c9787b05b73ab22ae53af3e2"),
6956 hex!("a0d9990bf0b810d1145ecb2b011fd68c63cc85564e6724166fd4a9520180706e5f"),
6957 hex!("a0f60eb4b12132a40df05d9bbdb88bbde0185a3f097f3c76bf4200c23eda26cf86"),
6958 hex!("a0ca976997ddaf06f18992f6207e4f6a05979d07acead96568058789017cc6d06b"),
6959 hex!("a04d78166b48044fdc28ed22d2fd39c8df6f8aaa04cb71d3a17286856f6893ff83"),
6960 hex!("a021d4f90c34d3f1706e78463b6482bca77a3aa1cd059a3f326c42a1cfd30b9b60"),
6961 hex!("a0fc3b71c33e2e6b77c5e494c1db7fdbb447473f003daf378c7a63ba9bf3f0049d"),
6962 hex!("a0e33ed2be194a3d93d343e85642447c93a9d0cfc47a016c2c23d14c083be32a7c"),
6963 hex!("a07b8e7a21c1178d28074f157b50fca85ee25c12568ff8e9706dcbcdacb77bf854"),
6964 hex!("a0973274526811393ea0bf4811ca9077531db00d06b86237a2ecd683f55ba4bcb0"),
6965 hex!("a03a93d726d7487874e51b52d8d534c63aa2a689df18e3b307c0d6cb0a388b00f3"),
6966 hex!("a06aa67101d011d1c22fe739ef83b04b5214a3e2f8e1a2625d8bfdb116b447e86f"),
6967 hex!("a02dd545b33c62d33a183e127a08a4767fba891d9f3b94fc20a2ca02600d6d1fff"),
6968 hex!("a0fe6db87d00f06d53bff8169fa497571ff5af1addfb715b649b4d79dd3e394b04"),
6969 hex!("a0d9240a9d2d5851d05a97ff3305334dfdb0101e1e321fc279d2bb3cad6afa8fc8"),
6970 hex!("a01b69c6ab5173de8a8ec53a6ebba965713a4cc7feb86cb3e230def37c230ca2b2"),
6971 ];
6972
6973 let branch_0x3_rlp_stack: Vec<RlpNode> = branch_0x3_stack
6974 .iter()
6975 .map(|hex_str| RlpNode::from_raw_rlp(&hex_str[..]).unwrap())
6976 .collect();
6977
6978 let branch_0x3_node = BranchNodeV2::new(
6979 Default::default(),
6980 branch_0x3_rlp_stack,
6981 TrieMask::new(0b1111111111111111), None,
6983 );
6984
6985 let branch_0x3_masks = Some(BranchNodeMasks {
6986 hash_mask: TrieMask::new(0b0100010000010101),
6987 tree_mask: TrieMask::new(0b0100000000000000),
6988 });
6989
6990 let leaf_path = Nibbles::from_nibbles([0x3, 0x7]);
6992 let leaf_key = Nibbles::unpack(
6993 &hex!("d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42")[..],
6994 );
6995 let leaf_value = hex!("f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0f57acd40259872606d76197ef052f3d35588dadf919ee1f0e3cb9b62d3f4b02c").to_vec();
6996
6997 let leaf_node = LeafNode::new(leaf_key, leaf_value);
6998 let leaf_masks = None;
6999
7000 trie.reveal_nodes(&mut [
7001 ProofTrieNodeV2 {
7002 path: Nibbles::from_nibbles([0x3]),
7003 node: TrieNodeV2::Branch(branch_0x3_node),
7004 masks: branch_0x3_masks,
7005 },
7006 ProofTrieNodeV2 {
7007 path: leaf_path,
7008 node: TrieNodeV2::Leaf(leaf_node),
7009 masks: leaf_masks,
7010 },
7011 ])
7012 .unwrap();
7013
7014 let mut leaf_full_path = leaf_path;
7016 leaf_full_path.extend(&leaf_key);
7017
7018 let leaf_new_value = vec![
7019 248, 68, 1, 128, 160, 224, 163, 152, 169, 122, 160, 155, 102, 53, 41, 0, 47, 28, 205,
7020 190, 199, 5, 215, 108, 202, 22, 138, 70, 196, 178, 193, 208, 18, 96, 95, 63, 238, 160,
7021 245, 122, 205, 64, 37, 152, 114, 96, 109, 118, 25, 126, 240, 82, 243, 211, 85, 136,
7022 218, 223, 145, 158, 225, 240, 227, 203, 155, 98, 211, 244, 176, 44,
7023 ];
7024
7025 trie.update_leaf(leaf_full_path, leaf_new_value.clone()).unwrap();
7026
7027 assert_eq!(
7029 Some(&leaf_new_value),
7030 trie.lower_subtrie_for_path(&leaf_path).unwrap().inner.values.get(&leaf_full_path)
7031 );
7032 assert!(trie.upper_subtrie.inner.values.is_empty());
7033
7034 let expected_root =
7036 b256!("0x29b07de8376e9ce7b3a69e9b102199869514d3f42590b5abc6f7d48ec9b8665c");
7037 assert_eq!(trie.root(), expected_root);
7038 }
7039
7040 #[test]
7041 fn find_leaf_existing_leaf() {
7042 let mut sparse = ParallelSparseTrie::default();
7044 let path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3]));
7045 let value = b"test_value".to_vec();
7046
7047 sparse.update_leaf(path, value.clone()).unwrap();
7048
7049 let result = sparse.find_leaf(&path, None);
7051 assert_matches!(result, Ok(LeafLookup::Exists));
7052
7053 let result = sparse.find_leaf(&path, Some(&value));
7055 assert_matches!(result, Ok(LeafLookup::Exists));
7056 }
7057
7058 #[test]
7059 fn find_leaf_value_mismatch() {
7060 let mut sparse = ParallelSparseTrie::default();
7062 let path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3]));
7063 let value = b"test_value".to_vec();
7064 let wrong_value = b"wrong_value".to_vec();
7065
7066 sparse.update_leaf(path, value).unwrap();
7067
7068 let result = sparse.find_leaf(&path, Some(&wrong_value));
7070 assert_matches!(
7071 result,
7072 Err(LeafLookupError::ValueMismatch { path: p, expected: Some(e), actual: _a }) if p == path && e == wrong_value
7073 );
7074 }
7075
7076 #[test]
7077 fn find_leaf_not_found_empty_trie() {
7078 let sparse = ParallelSparseTrie::default();
7080 let path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
7081
7082 let result = sparse.find_leaf(&path, None);
7084 assert_matches!(result, Ok(LeafLookup::NonExistent));
7085 }
7086
7087 #[test]
7088 fn find_leaf_empty_trie() {
7089 let sparse = ParallelSparseTrie::default();
7090 let path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7091
7092 let result = sparse.find_leaf(&path, None);
7093 assert_matches!(result, Ok(LeafLookup::NonExistent));
7094 }
7095
7096 #[test]
7097 fn find_leaf_exists_no_value_check() {
7098 let mut sparse = ParallelSparseTrie::default();
7099 let path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
7100 sparse.update_leaf(path, encode_account_value(0)).unwrap();
7101
7102 let result = sparse.find_leaf(&path, None);
7103 assert_matches!(result, Ok(LeafLookup::Exists));
7104 }
7105
7106 #[test]
7107 fn find_leaf_exists_with_value_check_ok() {
7108 let mut sparse = ParallelSparseTrie::default();
7109 let path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
7110 let value = encode_account_value(0);
7111 sparse.update_leaf(path, value.clone()).unwrap();
7112
7113 let result = sparse.find_leaf(&path, Some(&value));
7114 assert_matches!(result, Ok(LeafLookup::Exists));
7115 }
7116
7117 #[test]
7118 fn find_leaf_exclusion_branch_divergence() {
7119 let mut sparse = ParallelSparseTrie::default();
7120 let path1 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4])); let path2 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x5, 0x6])); let search_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x7, 0x8])); sparse.update_leaf(path1, encode_account_value(0)).unwrap();
7125 sparse.update_leaf(path2, encode_account_value(1)).unwrap();
7126
7127 let result = sparse.find_leaf(&search_path, None);
7128 assert_matches!(result, Ok(LeafLookup::NonExistent))
7129 }
7130
7131 #[test]
7132 fn find_leaf_exclusion_extension_divergence() {
7133 let mut sparse = ParallelSparseTrie::default();
7134 let path1 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]));
7136 let search_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x7, 0x8]));
7138
7139 sparse.update_leaf(path1, encode_account_value(0)).unwrap();
7140
7141 let result = sparse.find_leaf(&search_path, None);
7142 assert_matches!(result, Ok(LeafLookup::NonExistent))
7143 }
7144
7145 #[test]
7146 fn find_leaf_exclusion_leaf_divergence() {
7147 let mut sparse = ParallelSparseTrie::default();
7148 let existing_leaf_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
7149 let search_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]));
7150
7151 sparse.update_leaf(existing_leaf_path, encode_account_value(0)).unwrap();
7152
7153 let result = sparse.find_leaf(&search_path, None);
7154 assert_matches!(result, Ok(LeafLookup::NonExistent))
7155 }
7156
7157 #[test]
7158 fn find_leaf_exclusion_path_ends_at_branch() {
7159 let mut sparse = ParallelSparseTrie::default();
7160 let path1 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4])); let path2 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x5, 0x6]));
7162 let search_path = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2])); sparse.update_leaf(path1, encode_account_value(0)).unwrap();
7165 sparse.update_leaf(path2, encode_account_value(1)).unwrap();
7166
7167 let result = sparse.find_leaf(&search_path, None);
7168 assert_matches!(result, Ok(LeafLookup::NonExistent));
7169 }
7170
7171 #[test]
7172 fn find_leaf_error_blinded_node_at_leaf_path() {
7173 let blinded_hash = B256::repeat_byte(0xBB);
7175 let leaf_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7176
7177 let sparse = new_test_trie(
7178 [
7179 (
7180 Nibbles::default(),
7182 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x1, 0x2])),
7183 ),
7184 (
7185 Nibbles::from_nibbles_unchecked([0x1, 0x2]),
7187 SparseNode::new_ext(Nibbles::from_nibbles_unchecked([0x3])),
7188 ),
7189 (
7190 Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3]),
7192 SparseNode::new_branch(TrieMask::new(0b10000), &[(0x4, blinded_hash)]),
7193 ),
7194 ]
7195 .into_iter(),
7196 );
7197
7198 let result = sparse.find_leaf(&leaf_path, None);
7199
7200 assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
7202 if path == leaf_path && hash == blinded_hash
7203 );
7204 }
7205
7206 #[test]
7207 fn find_leaf_error_blinded_node() {
7208 let blinded_hash = B256::repeat_byte(0xAA);
7209 let path_to_blind = Nibbles::from_nibbles_unchecked([0x1]);
7210 let search_path = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
7211
7212 let sparse = new_test_trie(
7213 [
7214 (
7217 Nibbles::default(),
7218 SparseNode::new_branch(TrieMask::new(0b100010), &[(0x1, blinded_hash)]),
7219 ),
7220 (
7221 Nibbles::from_nibbles_unchecked([0x5]),
7222 SparseNode::new_leaf(Nibbles::from_nibbles_unchecked([0x6, 0x7, 0x8])),
7223 ),
7224 ]
7225 .into_iter(),
7226 );
7227
7228 let result = sparse.find_leaf(&search_path, None);
7229
7230 assert_matches!(result, Err(LeafLookupError::BlindedNode { path, hash })
7232 if path == path_to_blind && hash == blinded_hash
7233 );
7234 }
7235
7236 #[test]
7237 fn test_mainnet_block_24185431_storage_0x6ba784ee() {
7238 reth_tracing::init_test_tracing();
7239
7240 let mut branch_0x3_hashes = vec![
7242 B256::from(hex!("fc11ba8de4b220b8f19a09f0676c69b8e18bae1350788392640069e59b41733d")),
7243 B256::from(hex!("8afe085cc6685680bd8ba4bac6e65937a4babf737dc5e7413d21cdda958e8f74")),
7244 B256::from(hex!("c7b6f7c0fc601a27aece6ec178fd9be17cdee77c4884ecfbe1ee459731eb57da")),
7245 B256::from(hex!("71c1aec60db78a2deb4e10399b979a2ed5be42b4ee0c0a17c614f9ddc9f9072e")),
7246 B256::from(hex!("e9261302e7c0b77930eaf1851b585210906cd01e015ab6be0f7f3c0cc947c32a")),
7247 B256::from(hex!("38ce8f369c56bd77fabdf679b27265b1f8d0a54b09ef612c8ee8ddfc6b3fab95")),
7248 B256::from(hex!("7b507a8936a28c5776b647d1c4bda0bbbb3d0d227f16c5f5ebba58d02e31918d")),
7249 B256::from(hex!("0f456b9457a824a81e0eb555aa861461acb38674dcf36959b3b26deb24ed0af9")),
7250 B256::from(hex!("2145420289652722ad199ba932622e3003c779d694fa5a2acfb2f77b0782b38a")),
7251 B256::from(hex!("2c1a04dce1a9e2f1cfbf8806edce50a356dfa58e7e7c542c848541502613b796")),
7252 B256::from(hex!("dad7ca55186ac8f40d4450dc874166df8267b44abc07e684d9507260f5712df3")),
7253 B256::from(hex!("3a8c2a1d7d2423e92965ec29014634e7f0307ded60b1a63d28c86c3222b24236")),
7254 B256::from(hex!("4e9929e6728b3a7bf0db6a0750ab376045566b556c9c605e606ecb8ec25200d7")),
7255 B256::from(hex!("1797c36f98922f52292c161590057a1b5582d5503e3370bcfbf6fd939f3ec98b")),
7256 B256::from(hex!("9e514589a9c9210b783c19fa3f0b384bbfaefe98f10ea189a2bfc58c6bf000a1")),
7257 B256::from(hex!("85bdaabbcfa583cbd049650e41d3d19356bd833b3ed585cf225a3548557c7fa3")),
7258 ];
7259 let branch_0x3_node = create_branch_node(
7260 Nibbles::from_nibbles([0x3]),
7261 &[0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf],
7262 branch_0x3_hashes.iter().map(RlpNode::word_rlp),
7263 );
7264
7265 let branch_0x31_hashes = vec![B256::from(hex!(
7267 "3ca994ba59ce70b83fee1f01731c8dac4fdd0f70ade79bf9b0695c4c53531aab"
7268 ))];
7269 let branch_0x31_node = create_branch_node_with_children(
7270 &[0xc],
7271 branch_0x31_hashes.into_iter().map(|h| RlpNode::word_rlp(&h)),
7272 );
7273
7274 let leaf_path = hex!("31b0b645a6c4a0a1bb3d2f0c1d31c39f4aba2e3b015928a8eef7161e28388b81");
7276 let leaf_nibbles = Nibbles::unpack(leaf_path.as_slice());
7277 let leaf_value = hex!("0009ae8ce8245bff").to_vec();
7278
7279 let branch_0x31c_hashes = vec![
7281 B256::from(hex!("1a68fdb36b77e9332b49a977faf800c22d0199e6cecf44032bb083c78943e540")),
7282 B256::from(hex!("cd4622c6df6fd7172c7fed1b284ef241e0f501b4c77b675ef10c612bd0948a7a")),
7283 B256::from(hex!("abf3603d2f991787e21f1709ee4c7375d85dfc506995c0435839fccf3fe2add4")),
7284 ];
7285 let branch_0x31c_node = create_branch_node_with_children(
7286 &[0x3, 0x7, 0xc],
7287 branch_0x31c_hashes.into_iter().map(|h| RlpNode::word_rlp(&h)),
7288 );
7289
7290 let mut proof_nodes = vec![ProofTrieNodeV2 {
7292 path: Nibbles::from_nibbles([0x3, 0x1]),
7293 node: branch_0x31_node,
7294 masks: Some(BranchNodeMasks {
7295 tree_mask: TrieMask::new(4096),
7296 hash_mask: TrieMask::new(4096),
7297 }),
7298 }];
7299
7300 let mut trie = ParallelSparseTrie::default()
7302 .with_root(
7303 branch_0x3_node,
7304 Some(BranchNodeMasks {
7305 tree_mask: TrieMask::new(26099),
7306 hash_mask: TrieMask::new(65535),
7307 }),
7308 true,
7309 )
7310 .expect("root revealed");
7311
7312 trie.reveal_nodes(&mut proof_nodes).unwrap();
7313
7314 trie.update_leaf(leaf_nibbles, leaf_value).unwrap();
7316
7317 let Err(err) = trie.remove_leaf(&leaf_nibbles) else {
7319 panic!("expected blinded node error");
7320 };
7321 assert_matches!(err.kind(), SparseTrieErrorKind::BlindedNode(path) if path == &Nibbles::from_nibbles([0x3, 0x1, 0xc]));
7322
7323 trie.reveal_nodes(&mut [ProofTrieNodeV2 {
7324 path: Nibbles::from_nibbles([0x3, 0x1, 0xc]),
7325 node: branch_0x31c_node,
7326 masks: Some(BranchNodeMasks { tree_mask: 0.into(), hash_mask: 4096.into() }),
7327 }])
7328 .unwrap();
7329
7330 trie.remove_leaf(&leaf_nibbles).unwrap();
7332
7333 let _ = trie.root();
7335
7336 let updates = trie.updates_ref();
7338
7339 let branch_0x3_update = updates
7341 .updated_nodes
7342 .get(&Nibbles::from_nibbles([0x3]))
7343 .expect("Branch at 0x3 should be in updates");
7344
7345 branch_0x3_hashes.remove(1);
7347
7348 let expected_branch = BranchNodeCompact::new(
7350 0b1111111111111111,
7351 0b0110010111110011,
7352 0b1111111111111101,
7353 branch_0x3_hashes,
7354 None,
7355 );
7356
7357 assert_eq!(branch_0x3_update, &expected_branch);
7358 }
7359
7360 #[test]
7361 fn test_get_leaf_value_lower_subtrie() {
7362 let root_branch =
7368 create_branch_node_with_children(&[0x1], [RlpNode::word_rlp(&B256::repeat_byte(0xAA))]);
7369 let branch_at_1 =
7370 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xBB))]);
7371 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
7372 trie.reveal_nodes(&mut [ProofTrieNodeV2 {
7373 path: Nibbles::from_nibbles([0x1]),
7374 node: branch_at_1,
7375 masks: None,
7376 }])
7377 .unwrap();
7378
7379 let leaf_path = Nibbles::from_nibbles([0x1, 0x2]);
7381 let leaf_key = Nibbles::from_nibbles([0x3, 0x4]);
7382 let leaf_node = create_leaf_node(leaf_key.to_vec(), 42);
7383
7384 trie.reveal_nodes(&mut [ProofTrieNodeV2 { path: leaf_path, node: leaf_node, masks: None }])
7386 .unwrap();
7387
7388 let full_path = Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]);
7390
7391 let idx = path_subtrie_index_unchecked(&leaf_path);
7393 let lower_subtrie = trie.lower_subtries[idx].as_revealed_ref().unwrap();
7394 assert!(
7395 lower_subtrie.inner.values.contains_key(&full_path),
7396 "value should be in lower subtrie"
7397 );
7398 assert!(
7399 !trie.upper_subtrie.inner.values.contains_key(&full_path),
7400 "value should NOT be in upper subtrie"
7401 );
7402
7403 assert!(
7405 trie.get_leaf_value(&full_path).is_some(),
7406 "get_leaf_value should find the value in lower subtrie"
7407 );
7408 }
7409
7410 #[test]
7417 fn test_get_leaf_value_upper_subtrie_via_update_leaf() {
7418 let mut trie = ParallelSparseTrie::default()
7420 .with_root(TrieNodeV2::EmptyRoot, None, false)
7421 .expect("root revealed");
7422
7423 let full_path = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0xA, 0xB, 0xC]));
7425 let value = encode_account_value(42);
7426
7427 trie.update_leaf(full_path, value.clone()).unwrap();
7430
7431 assert!(
7433 trie.upper_subtrie.inner.values.contains_key(&full_path),
7434 "value should be in upper subtrie after update_leaf"
7435 );
7436
7437 let retrieved = trie.get_leaf_value(&full_path);
7441 assert_eq!(retrieved, Some(&value));
7442 }
7443
7444 #[test]
7446 fn test_get_leaf_value_upper_and_lower_subtries() {
7447 let mut trie = ParallelSparseTrie::default()
7449 .with_root(TrieNodeV2::EmptyRoot, None, false)
7450 .expect("root revealed");
7451
7452 let path1 = pad_nibbles_right(Nibbles::from_nibbles([0x0, 0xA]));
7454 let value1 = encode_account_value(1);
7455 trie.update_leaf(path1, value1.clone()).unwrap();
7456
7457 let path2 = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0xB]));
7459 let value2 = encode_account_value(2);
7460 trie.update_leaf(path2, value2.clone()).unwrap();
7461
7462 assert_eq!(trie.get_leaf_value(&path1), Some(&value1));
7464 assert_eq!(trie.get_leaf_value(&path2), Some(&value2));
7465 }
7466
7467 #[test]
7469 fn test_get_leaf_value_sparse_storage_trie() {
7470 let mut trie = ParallelSparseTrie::default()
7472 .with_root(TrieNodeV2::EmptyRoot, None, false)
7473 .expect("root revealed");
7474
7475 let slot_path = pad_nibbles_right(Nibbles::from_nibbles([0x2, 0x9]));
7477 let slot_value = alloy_rlp::encode(U256::from(12345));
7478 trie.update_leaf(slot_path, slot_value.clone()).unwrap();
7479
7480 assert_eq!(trie.get_leaf_value(&slot_path), Some(&slot_value));
7482 }
7483
7484 #[test]
7485 fn test_prune_empty_suffix_key_regression() {
7486 let mut parallel = ParallelSparseTrie::default();
7490
7491 let value = {
7493 let account = Account {
7494 nonce: 0x123456789abcdef,
7495 balance: U256::from(0x123456789abcdef0123456789abcdef_u128),
7496 ..Default::default()
7497 };
7498 let mut buf = Vec::new();
7499 account.into_trie_account(EMPTY_ROOT_HASH).encode(&mut buf);
7500 buf
7501 };
7502
7503 for i in 0..16u8 {
7505 parallel
7506 .update_leaf(
7507 pad_nibbles_right(Nibbles::from_nibbles([i, 0x1, 0x2, 0x3, 0x4, 0x5])),
7508 value.clone(),
7509 )
7510 .unwrap();
7511 }
7512
7513 let root_before = parallel.root();
7515
7516 parallel.prune(&[]);
7518
7519 let root_after = parallel.root();
7520 assert_eq!(root_before, root_after, "root hash must be preserved");
7521
7522 for i in 0..16u8 {
7525 let path = pad_nibbles_right(Nibbles::from_nibbles([i, 0x1, 0x2, 0x3, 0x4, 0x5]));
7526 assert!(
7527 parallel.get_leaf_value(&path).is_none(),
7528 "value at {:?} should be removed after prune",
7529 path
7530 );
7531 }
7532 }
7533
7534 #[test]
7535 fn test_prune_empty_trie() {
7536 let mut trie = ParallelSparseTrie::default();
7537 trie.prune(&[]);
7538 let root = trie.root();
7539 assert_eq!(root, EMPTY_ROOT_HASH, "empty trie should have empty root hash");
7540 }
7541
7542 #[test]
7543 fn test_prune_preserves_root_hash() {
7544 let mut trie = ParallelSparseTrie::default();
7545
7546 let value = large_account_value();
7547
7548 for i in 0..8u8 {
7549 for j in 0..4u8 {
7550 trie.update_leaf(
7551 pad_nibbles_right(Nibbles::from_nibbles([i, j, 0x3, 0x4, 0x5, 0x6])),
7552 value.clone(),
7553 )
7554 .unwrap();
7555 }
7556 }
7557
7558 let root_before = trie.root();
7559 trie.prune(&[]);
7560 let root_after = trie.root();
7561 assert_eq!(root_before, root_after, "root hash must be preserved after prune");
7562 }
7563
7564 #[test]
7565 fn test_prune_single_leaf_trie() {
7566 let mut trie = ParallelSparseTrie::default();
7567
7568 let value = large_account_value();
7569 trie.update_leaf(pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4])), value)
7570 .unwrap();
7571
7572 let root_before = trie.root();
7573 let nodes_before = trie.size_hint();
7574
7575 trie.prune(&[]);
7576
7577 let root_after = trie.root();
7578 assert_eq!(root_before, root_after, "root hash should be preserved");
7579 assert_eq!(trie.size_hint(), nodes_before, "single leaf trie should not change");
7580 }
7581
7582 #[test]
7583 fn test_prune_root_hash_preserved() {
7584 let mut trie = ParallelSparseTrie::default();
7585
7586 let key1 = Nibbles::unpack(B256::repeat_byte(0x00));
7588 let key2 = Nibbles::unpack(B256::repeat_byte(0x11));
7589
7590 let large_value = large_account_value();
7591 trie.update_leaf(key1, large_value.clone()).unwrap();
7592 trie.update_leaf(key2, large_value).unwrap();
7593
7594 let root_before = trie.root();
7595
7596 trie.prune(&[]);
7597
7598 assert_eq!(root_before, trie.root(), "root hash must be preserved after pruning");
7599 }
7600
7601 #[test]
7602 fn test_prune_mixed_embedded_and_hashed() {
7603 let mut trie = ParallelSparseTrie::default();
7604
7605 let large_value = large_account_value();
7606 let small_value = vec![0x80];
7607
7608 for i in 0..8u8 {
7609 let value = if i < 4 { large_value.clone() } else { small_value.clone() };
7610 trie.update_leaf(pad_nibbles_right(Nibbles::from_nibbles([i, 0x1, 0x2, 0x3])), value)
7611 .unwrap();
7612 }
7613
7614 let root_before = trie.root();
7615 trie.prune(&[]);
7616 assert_eq!(root_before, trie.root(), "root hash must be preserved");
7617 }
7618
7619 #[test]
7620 fn test_prune_all_lower_subtries() {
7621 let large_value = large_account_value();
7622
7623 let mut keys = Vec::new();
7624 for first in 0..16u8 {
7625 for second in 0..16u8 {
7626 keys.push(pad_nibbles_right(Nibbles::from_nibbles([
7627 first, second, 0x1, 0x2, 0x3, 0x4,
7628 ])));
7629 }
7630 }
7631
7632 let mut trie = ParallelSparseTrie::default();
7633
7634 for key in &keys {
7635 trie.update_leaf(*key, large_value.clone()).unwrap();
7636 }
7637
7638 let root_before = trie.root();
7639
7640 let total_pruned = trie.prune(&[]);
7641
7642 assert!(total_pruned > 0, "should have pruned some nodes");
7643 assert_eq!(root_before, trie.root(), "root hash should be preserved");
7644
7645 for key in &keys {
7646 assert!(trie.get_leaf_value(key).is_none(), "value should be pruned");
7647 }
7648 }
7649
7650 #[test]
7651 fn test_prune_keeps_only_hot_paths() {
7652 let mut trie = ParallelSparseTrie::default();
7653
7654 let key_keep = pad_nibbles_right(Nibbles::from_nibbles([0x1, 0x2, 0x3, 0x4]));
7655 let key_drop_1 = pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x2, 0x3, 0x4]));
7656 let key_drop_2 = pad_nibbles_right(Nibbles::from_nibbles([0x9, 0x2, 0x3, 0x4]));
7657
7658 let value = large_account_value();
7659 trie.update_leaf(key_keep, value.clone()).unwrap();
7660 trie.update_leaf(key_drop_1, value.clone()).unwrap();
7661 trie.update_leaf(key_drop_2, value).unwrap();
7662
7663 let root_before = trie.root();
7664
7665 let pruned = trie.prune(&[key_keep]);
7666 assert!(pruned > 0, "expected some nodes to be pruned");
7667 assert_eq!(root_before, trie.root(), "root hash should be preserved after LFU prune");
7668
7669 assert!(trie.get_leaf_value(&key_keep).is_some(), "retained key must remain revealed");
7670 assert!(trie.get_leaf_value(&key_drop_1).is_none(), "non-retained key should be pruned");
7671 assert!(trie.get_leaf_value(&key_drop_2).is_none(), "non-retained key should be pruned");
7672 }
7673
7674 #[test]
7675 fn test_prune_update_after() {
7676 let mut trie = ParallelSparseTrie::default();
7678
7679 let value = large_account_value();
7680
7681 for first in 0..4u8 {
7683 for second in 0..4u8 {
7684 trie.update_leaf(
7685 pad_nibbles_right(Nibbles::from_nibbles([
7686 first, second, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6,
7687 ])),
7688 value.clone(),
7689 )
7690 .unwrap();
7691 }
7692 }
7693
7694 let root_before = trie.root();
7695
7696 trie.prune(&[]);
7697
7698 let root_after = trie.root();
7699 assert_eq!(root_before, root_after, "root hash should be preserved");
7700
7701 let new_path =
7704 pad_nibbles_right(Nibbles::from_nibbles([0x5, 0x5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6]));
7705 trie.update_leaf(new_path, value).unwrap();
7706
7707 let _ = trie.root();
7709 }
7710
7711 #[test]
7714 fn test_update_leaves_successful_update() {
7715 use crate::LeafUpdate;
7716 use alloy_primitives::map::B256Map;
7717 use std::cell::RefCell;
7718 let mut trie = ParallelSparseTrie::default();
7719
7720 let b256_key = B256::with_last_byte(42);
7722 let key = Nibbles::unpack(b256_key);
7723 let value = encode_account_value(1);
7724 trie.update_leaf(key, value).unwrap();
7725
7726 let new_value = encode_account_value(2);
7728
7729 let mut updates: B256Map<LeafUpdate> = B256Map::default();
7730 updates.insert(b256_key, LeafUpdate::Changed(new_value));
7731
7732 let proof_targets = RefCell::new(Vec::new());
7733 trie.update_leaves(&mut updates, |path, min_len| {
7734 proof_targets.borrow_mut().push((path, min_len));
7735 })
7736 .unwrap();
7737
7738 assert!(updates.is_empty(), "Update map should be empty after successful update");
7740 assert!(
7741 proof_targets.borrow().is_empty(),
7742 "Callback should not be invoked for revealed paths"
7743 );
7744 }
7745
7746 #[test]
7747 fn test_update_leaves_insert_new_leaf() {
7748 use crate::LeafUpdate;
7749 use alloy_primitives::map::B256Map;
7750 use std::cell::RefCell;
7751
7752 let mut trie = ParallelSparseTrie::default();
7753
7754 let b256_key = B256::with_last_byte(99);
7756 let new_value = encode_account_value(42);
7757
7758 let mut updates: B256Map<LeafUpdate> = B256Map::default();
7759 updates.insert(b256_key, LeafUpdate::Changed(new_value.clone()));
7760
7761 let proof_targets = RefCell::new(Vec::new());
7762 trie.update_leaves(&mut updates, |path, min_len| {
7763 proof_targets.borrow_mut().push((path, min_len));
7764 })
7765 .unwrap();
7766
7767 assert!(updates.is_empty(), "Update map should be empty after successful insert");
7769 assert!(
7770 proof_targets.borrow().is_empty(),
7771 "Callback should not be invoked for new leaf insert"
7772 );
7773
7774 let full_path = Nibbles::unpack(b256_key);
7776 assert_eq!(
7777 trie.get_leaf_value(&full_path),
7778 Some(&new_value),
7779 "New leaf value should be retrievable"
7780 );
7781 }
7782
7783 #[test]
7784 fn test_update_leaves_blinded_node() {
7785 use crate::LeafUpdate;
7786 use alloy_primitives::map::B256Map;
7787 use std::cell::RefCell;
7788
7789 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
7792 let leaf = LeafNode::new(
7793 Nibbles::default(), small_value,
7795 );
7796 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
7797 Nibbles::default(),
7798 vec![
7799 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
7802 TrieMask::new(0b11),
7803 None,
7804 ));
7805
7806 let mut trie = ParallelSparseTrie::from_root(
7807 branch.clone(),
7808 Some(BranchNodeMasks {
7809 hash_mask: TrieMask::new(0b01),
7810 tree_mask: TrieMask::default(),
7811 }),
7812 false,
7813 )
7814 .unwrap();
7815
7816 trie.reveal_node(
7818 Nibbles::default(),
7819 branch,
7820 Some(BranchNodeMasks {
7821 hash_mask: TrieMask::default(),
7822 tree_mask: TrieMask::new(0b01),
7823 }),
7824 )
7825 .unwrap();
7826 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNodeV2::Leaf(leaf), None).unwrap();
7827
7828 let b256_key = B256::ZERO; let new_value = encode_account_value(42);
7833 let mut updates: B256Map<LeafUpdate> = B256Map::default();
7834 updates.insert(b256_key, LeafUpdate::Changed(new_value));
7835
7836 let proof_targets = RefCell::new(Vec::new());
7837 let prefix_set_len_before = trie.prefix_set.len();
7838 trie.update_leaves(&mut updates, |path, min_len| {
7839 proof_targets.borrow_mut().push((path, min_len));
7840 })
7841 .unwrap();
7842
7843 assert!(!updates.is_empty(), "Update should remain in map when hitting blinded node");
7845
7846 assert_eq!(
7848 trie.prefix_set.len(),
7849 prefix_set_len_before,
7850 "prefix_set should be unchanged after failed update on blinded node"
7851 );
7852
7853 let targets = proof_targets.borrow();
7855 assert!(!targets.is_empty(), "Callback should be invoked for blinded path");
7856
7857 assert_eq!(targets[0].1, 1, "min_len should equal blinded node path length");
7859 }
7860
7861 #[test]
7862 fn test_update_leaves_removal() {
7863 use crate::LeafUpdate;
7864 use alloy_primitives::map::B256Map;
7865 use std::cell::RefCell;
7866 let mut trie = ParallelSparseTrie::default();
7867
7868 let b256_key1 = B256::with_last_byte(1);
7871 let b256_key2 = B256::with_last_byte(2);
7872 let key1 = Nibbles::unpack(b256_key1);
7873 let key2 = Nibbles::unpack(b256_key2);
7874 let value = encode_account_value(1);
7875 trie.update_leaf(key1, value.clone()).unwrap();
7876 trie.update_leaf(key2, value).unwrap();
7877
7878 let mut updates: B256Map<LeafUpdate> = B256Map::default();
7880 updates.insert(b256_key1, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
7883 trie.update_leaves(&mut updates, |path, min_len| {
7884 proof_targets.borrow_mut().push((path, min_len));
7885 })
7886 .unwrap();
7887
7888 assert!(updates.is_empty(), "Update map should be empty after successful removal");
7890 }
7891
7892 #[test]
7893 fn test_update_leaves_removal_blinded() {
7894 use crate::LeafUpdate;
7895 use alloy_primitives::map::B256Map;
7896 use std::cell::RefCell;
7897
7898 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
7901 let leaf = LeafNode::new(
7902 Nibbles::default(), small_value,
7904 );
7905 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
7906 Nibbles::default(),
7907 vec![
7908 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
7911 TrieMask::new(0b11),
7912 None,
7913 ));
7914
7915 let mut trie = ParallelSparseTrie::from_root(
7916 branch.clone(),
7917 Some(BranchNodeMasks {
7918 hash_mask: TrieMask::new(0b01),
7919 tree_mask: TrieMask::default(),
7920 }),
7921 false,
7922 )
7923 .unwrap();
7924
7925 trie.reveal_node(
7926 Nibbles::default(),
7927 branch,
7928 Some(BranchNodeMasks {
7929 hash_mask: TrieMask::default(),
7930 tree_mask: TrieMask::new(0b01),
7931 }),
7932 )
7933 .unwrap();
7934 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNodeV2::Leaf(leaf), None).unwrap();
7935
7936 let b256_key = B256::ZERO; let full_path = Nibbles::unpack(b256_key);
7939
7940 let old_value = encode_account_value(99);
7942 trie.upper_subtrie.inner.values.insert(full_path, old_value.clone());
7943
7944 let mut updates: B256Map<LeafUpdate> = B256Map::default();
7945 updates.insert(b256_key, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
7948 let prefix_set_len_before = trie.prefix_set.len();
7949 trie.update_leaves(&mut updates, |path, min_len| {
7950 proof_targets.borrow_mut().push((path, min_len));
7951 })
7952 .unwrap();
7953
7954 assert!(
7956 !proof_targets.borrow().is_empty(),
7957 "Callback should be invoked when removal hits blinded node"
7958 );
7959
7960 assert!(!updates.is_empty(), "Update should remain in map when removal hits blinded node");
7962
7963 assert_eq!(
7965 trie.upper_subtrie.inner.values.get(&full_path),
7966 Some(&old_value),
7967 "Original value should be preserved after failed removal"
7968 );
7969
7970 assert_eq!(
7972 trie.prefix_set.len(),
7973 prefix_set_len_before,
7974 "prefix_set should be unchanged after failed removal on blinded node"
7975 );
7976 }
7977
7978 #[test]
7979 fn test_update_leaves_removal_branch_collapse_blinded() {
7980 use crate::LeafUpdate;
7981 use alloy_primitives::map::B256Map;
7982 use std::cell::RefCell;
7983
7984 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
7988 let leaf = LeafNode::new(Nibbles::default(), small_value);
7989 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
7990 Nibbles::default(),
7991 vec![
7992 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
7995 TrieMask::new(0b11),
7996 None,
7997 ));
7998
7999 let mut trie = ParallelSparseTrie::from_root(
8000 branch.clone(),
8001 Some(BranchNodeMasks {
8002 hash_mask: TrieMask::new(0b01), tree_mask: TrieMask::default(),
8004 }),
8005 false,
8006 )
8007 .unwrap();
8008
8009 trie.reveal_node(
8011 Nibbles::default(),
8012 branch,
8013 Some(BranchNodeMasks {
8014 hash_mask: TrieMask::default(),
8015 tree_mask: TrieMask::new(0b01),
8016 }),
8017 )
8018 .unwrap();
8019 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNodeV2::Leaf(leaf), None).unwrap();
8020
8021 let b256_key = B256::with_last_byte(0x10);
8024 let full_path = Nibbles::unpack(b256_key);
8025 let leaf_value = encode_account_value(42);
8026 trie.upper_subtrie.inner.values.insert(full_path, leaf_value.clone());
8027
8028 let prefix_set_len_before = trie.prefix_set.len();
8030 let node_count_before = trie.upper_subtrie.nodes.len() +
8031 trie.lower_subtries
8032 .iter()
8033 .filter_map(|s| s.as_revealed_ref())
8034 .map(|s| s.nodes.len())
8035 .sum::<usize>();
8036
8037 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8038 updates.insert(b256_key, LeafUpdate::Changed(vec![])); let proof_targets = RefCell::new(Vec::new());
8041 trie.update_leaves(&mut updates, |path, min_len| {
8042 proof_targets.borrow_mut().push((path, min_len));
8043 })
8044 .unwrap();
8045
8046 assert!(
8048 !updates.is_empty(),
8049 "Update should remain in map when removal would collapse branch with blinded sibling"
8050 );
8051
8052 assert!(
8054 !proof_targets.borrow().is_empty(),
8055 "Callback should be invoked for blinded sibling path"
8056 );
8057
8058 assert_eq!(
8060 trie.prefix_set.len(),
8061 prefix_set_len_before,
8062 "prefix_set should be unchanged after atomic failure"
8063 );
8064
8065 let node_count_after = trie.upper_subtrie.nodes.len() +
8067 trie.lower_subtries
8068 .iter()
8069 .filter_map(|s| s.as_revealed_ref())
8070 .map(|s| s.nodes.len())
8071 .sum::<usize>();
8072 assert_eq!(
8073 node_count_before, node_count_after,
8074 "Node count should be unchanged after atomic failure"
8075 );
8076
8077 assert_eq!(
8079 trie.upper_subtrie.inner.values.get(&full_path),
8080 Some(&leaf_value),
8081 "Leaf value should still exist after failed removal"
8082 );
8083 }
8084
8085 #[test]
8086 fn test_update_leaves_touched() {
8087 use crate::LeafUpdate;
8088 use alloy_primitives::map::B256Map;
8089 use std::cell::RefCell;
8090 let mut trie = ParallelSparseTrie::default();
8091
8092 let b256_key = B256::with_last_byte(42);
8094 let key = Nibbles::unpack(b256_key);
8095 let value = encode_account_value(1);
8096 trie.update_leaf(key, value).unwrap();
8097
8098 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8100 updates.insert(b256_key, LeafUpdate::Touched);
8101
8102 let proof_targets = RefCell::new(Vec::new());
8103 let prefix_set_len_before = trie.prefix_set.len();
8104
8105 trie.update_leaves(&mut updates, |path, min_len| {
8106 proof_targets.borrow_mut().push((path, min_len));
8107 })
8108 .unwrap();
8109
8110 assert!(updates.is_empty(), "Touched update should be removed for accessible path");
8112
8113 assert!(
8115 proof_targets.borrow().is_empty(),
8116 "Callback should not be invoked for accessible path"
8117 );
8118
8119 assert_eq!(
8121 trie.prefix_set.len(),
8122 prefix_set_len_before,
8123 "prefix_set should be unchanged for Touched update (read-only)"
8124 );
8125 }
8126
8127 #[test]
8128 fn test_update_leaves_touched_nonexistent() {
8129 use crate::LeafUpdate;
8130 use alloy_primitives::map::B256Map;
8131 use std::cell::RefCell;
8132
8133 let mut trie = ParallelSparseTrie::default();
8134
8135 let b256_key = B256::with_last_byte(99);
8137 let full_path = Nibbles::unpack(b256_key);
8138
8139 let prefix_set_len_before = trie.prefix_set.len();
8140
8141 let mut updates: B256Map<LeafUpdate> = B256Map::default();
8142 updates.insert(b256_key, LeafUpdate::Touched);
8143
8144 let proof_targets = RefCell::new(Vec::new());
8145 trie.update_leaves(&mut updates, |path, min_len| {
8146 proof_targets.borrow_mut().push((path, min_len));
8147 })
8148 .unwrap();
8149
8150 assert!(updates.is_empty(), "Touched update should be removed for accessible (empty) path");
8152
8153 assert!(
8155 proof_targets.borrow().is_empty(),
8156 "Callback should not be invoked for accessible path"
8157 );
8158
8159 assert_eq!(
8161 trie.prefix_set.len(),
8162 prefix_set_len_before,
8163 "prefix_set should not be modified by Touched update"
8164 );
8165
8166 assert!(
8168 trie.get_leaf_value(&full_path).is_none(),
8169 "No value should exist for non-existent key after Touched update"
8170 );
8171 }
8172
8173 #[test]
8174 fn test_update_leaves_touched_blinded() {
8175 use crate::LeafUpdate;
8176 use alloy_primitives::map::B256Map;
8177 use std::cell::RefCell;
8178
8179 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8182 let leaf = LeafNode::new(
8183 Nibbles::default(), small_value,
8185 );
8186 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
8187 Nibbles::default(),
8188 vec![
8189 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8192 TrieMask::new(0b11),
8193 None,
8194 ));
8195
8196 let mut trie = ParallelSparseTrie::from_root(
8197 branch.clone(),
8198 Some(BranchNodeMasks {
8199 hash_mask: TrieMask::new(0b01),
8200 tree_mask: TrieMask::default(),
8201 }),
8202 false,
8203 )
8204 .unwrap();
8205
8206 trie.reveal_node(
8207 Nibbles::default(),
8208 branch,
8209 Some(BranchNodeMasks {
8210 hash_mask: TrieMask::default(),
8211 tree_mask: TrieMask::new(0b01),
8212 }),
8213 )
8214 .unwrap();
8215 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNodeV2::Leaf(leaf), None).unwrap();
8216
8217 let b256_key = B256::ZERO; let mut updates: B256Map<LeafUpdate> = B256Map::default();
8221 updates.insert(b256_key, LeafUpdate::Touched);
8222
8223 let proof_targets = RefCell::new(Vec::new());
8224 let prefix_set_len_before = trie.prefix_set.len();
8225 trie.update_leaves(&mut updates, |path, min_len| {
8226 proof_targets.borrow_mut().push((path, min_len));
8227 })
8228 .unwrap();
8229
8230 assert!(!proof_targets.borrow().is_empty(), "Callback should be invoked for blinded path");
8232
8233 assert!(!updates.is_empty(), "Touched update should remain in map for blinded path");
8235
8236 assert_eq!(
8238 trie.prefix_set.len(),
8239 prefix_set_len_before,
8240 "prefix_set should be unchanged for Touched update on blinded path"
8241 );
8242 }
8243
8244 #[test]
8245 fn test_update_leaves_deduplication() {
8246 use crate::LeafUpdate;
8247 use alloy_primitives::map::B256Map;
8248 use std::cell::RefCell;
8249
8250 let small_value = alloy_rlp::encode_fixed_size(&U256::from(1)).to_vec();
8253 let leaf = LeafNode::new(
8254 Nibbles::default(), small_value,
8256 );
8257 let branch = TrieNodeV2::Branch(BranchNodeV2::new(
8258 Nibbles::default(),
8259 vec![
8260 RlpNode::word_rlp(&B256::repeat_byte(1)), RlpNode::from_raw_rlp(&alloy_rlp::encode(leaf.clone())).unwrap(), ],
8263 TrieMask::new(0b11),
8264 None,
8265 ));
8266
8267 let mut trie = ParallelSparseTrie::from_root(
8268 branch.clone(),
8269 Some(BranchNodeMasks {
8270 hash_mask: TrieMask::new(0b01),
8271 tree_mask: TrieMask::default(),
8272 }),
8273 false,
8274 )
8275 .unwrap();
8276
8277 trie.reveal_node(
8278 Nibbles::default(),
8279 branch,
8280 Some(BranchNodeMasks {
8281 hash_mask: TrieMask::default(),
8282 tree_mask: TrieMask::new(0b01),
8283 }),
8284 )
8285 .unwrap();
8286 trie.reveal_node(Nibbles::from_nibbles([0x1]), TrieNodeV2::Leaf(leaf), None).unwrap();
8287
8288 let b256_key1 = B256::ZERO;
8291 let b256_key2 = B256::with_last_byte(1); let b256_key3 = B256::with_last_byte(2); let mut updates: B256Map<LeafUpdate> = B256Map::default();
8295 let value = encode_account_value(42);
8296
8297 updates.insert(b256_key1, LeafUpdate::Changed(value.clone()));
8298 updates.insert(b256_key2, LeafUpdate::Changed(value.clone()));
8299 updates.insert(b256_key3, LeafUpdate::Changed(value));
8300
8301 let proof_targets = RefCell::new(Vec::new());
8302 trie.update_leaves(&mut updates, |path, min_len| {
8303 proof_targets.borrow_mut().push((path, min_len));
8304 })
8305 .unwrap();
8306
8307 let targets = proof_targets.borrow();
8310 assert_eq!(targets.len(), 3, "Callback should be invoked for each unique key");
8311
8312 for (_, min_len) in targets.iter() {
8314 assert_eq!(*min_len, 1, "All should have min_len 1 from blinded node at 0x0");
8315 }
8316 }
8317
8318 #[test]
8319 fn test_nibbles_to_padded_b256() {
8320 let empty = Nibbles::default();
8322 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&empty), B256::ZERO);
8323
8324 let full_key = b256!("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef");
8326 let full_nibbles = Nibbles::unpack(full_key);
8327 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&full_nibbles), full_key);
8328
8329 let partial = Nibbles::from_nibbles_unchecked([0x1, 0x2, 0x3, 0x4]);
8332 let expected = b256!("1234000000000000000000000000000000000000000000000000000000000000");
8333 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&partial), expected);
8334
8335 let single = Nibbles::from_nibbles_unchecked([0xf]);
8337 let expected_single =
8338 b256!("f000000000000000000000000000000000000000000000000000000000000000");
8339 assert_eq!(ParallelSparseTrie::nibbles_to_padded_b256(&single), expected_single);
8340 }
8341
8342 #[test]
8343 fn test_memory_size() {
8344 let trie = ParallelSparseTrie::default();
8346 let empty_size = trie.memory_size();
8347
8348 assert!(empty_size >= core::mem::size_of::<ParallelSparseTrie>());
8350
8351 let root_branch = create_branch_node_with_children(
8355 &[0x1, 0x5],
8356 [
8357 RlpNode::word_rlp(&B256::repeat_byte(0xAA)),
8358 RlpNode::word_rlp(&B256::repeat_byte(0xBB)),
8359 ],
8360 );
8361 let mut trie = ParallelSparseTrie::from_root(root_branch, None, false).unwrap();
8362
8363 let branch_at_1 =
8364 create_branch_node_with_children(&[0x2], [RlpNode::word_rlp(&B256::repeat_byte(0xCC))]);
8365 let branch_at_5 =
8366 create_branch_node_with_children(&[0x6], [RlpNode::word_rlp(&B256::repeat_byte(0xDD))]);
8367 trie.reveal_nodes(&mut [
8368 ProofTrieNodeV2 {
8369 path: Nibbles::from_nibbles_unchecked([0x1]),
8370 node: branch_at_1,
8371 masks: None,
8372 },
8373 ProofTrieNodeV2 {
8374 path: Nibbles::from_nibbles_unchecked([0x5]),
8375 node: branch_at_5,
8376 masks: None,
8377 },
8378 ])
8379 .unwrap();
8380
8381 let mut nodes = vec![
8382 ProofTrieNodeV2 {
8383 path: Nibbles::from_nibbles_unchecked([0x1, 0x2]),
8384 node: TrieNodeV2::Leaf(LeafNode {
8385 key: Nibbles::from_nibbles_unchecked([0x3, 0x4]),
8386 value: vec![1, 2, 3],
8387 }),
8388 masks: None,
8389 },
8390 ProofTrieNodeV2 {
8391 path: Nibbles::from_nibbles_unchecked([0x5, 0x6]),
8392 node: TrieNodeV2::Leaf(LeafNode {
8393 key: Nibbles::from_nibbles_unchecked([0x7, 0x8]),
8394 value: vec![4, 5, 6],
8395 }),
8396 masks: None,
8397 },
8398 ];
8399 trie.reveal_nodes(&mut nodes).unwrap();
8400
8401 let populated_size = trie.memory_size();
8402
8403 assert!(populated_size > empty_size);
8405 }
8406
8407 #[test]
8408 fn test_reveal_extension_branch_leaves_then_root() {
8409 let ext_key: [u8; 63] = [0; 63];
8420
8421 let branch_path = Nibbles::from_nibbles(ext_key);
8423
8424 let mut leaf1_path_bytes = [0u8; 64];
8426 leaf1_path_bytes[63] = 1;
8427 let leaf1_path = Nibbles::from_nibbles(leaf1_path_bytes);
8428
8429 let mut leaf2_path_bytes = [0u8; 64];
8430 leaf2_path_bytes[63] = 2;
8431 let leaf2_path = Nibbles::from_nibbles(leaf2_path_bytes);
8432
8433 let leaf1_node = LeafNode::new(Nibbles::default(), vec![0x1]);
8436 let leaf2_node = LeafNode::new(Nibbles::default(), vec![0x2]);
8437
8438 let leaf1_rlp = RlpNode::from_rlp(&alloy_rlp::encode(TrieNodeV2::Leaf(leaf1_node.clone())));
8440 let leaf2_rlp = RlpNode::from_rlp(&alloy_rlp::encode(TrieNodeV2::Leaf(leaf2_node.clone())));
8441
8442 let state_mask = TrieMask::new(0b0000_0110); let stack = vec![leaf1_rlp, leaf2_rlp];
8446
8447 let bare_branch = BranchNodeV2::new(Nibbles::new(), stack.clone(), state_mask, None);
8449 let branch_rlp = RlpNode::from_rlp(&alloy_rlp::encode(&bare_branch));
8450
8451 let root_node = TrieNodeV2::Branch(BranchNodeV2::new(
8453 Nibbles::from_nibbles(ext_key),
8454 stack.clone(),
8455 state_mask,
8456 Some(branch_rlp),
8457 ));
8458
8459 let mut trie = ParallelSparseTrie::from_root(root_node, None, false).unwrap();
8461
8462 let mut nodes = vec![
8464 ProofTrieNodeV2 {
8465 path: branch_path,
8466 node: TrieNodeV2::Branch(BranchNodeV2::new(
8467 Nibbles::new(),
8468 stack,
8469 state_mask,
8470 None,
8471 )),
8472 masks: None,
8473 },
8474 ProofTrieNodeV2 { path: leaf1_path, node: TrieNodeV2::Leaf(leaf1_node), masks: None },
8475 ProofTrieNodeV2 { path: leaf2_path, node: TrieNodeV2::Leaf(leaf2_node), masks: None },
8476 ];
8477 trie.reveal_nodes(&mut nodes).unwrap();
8478
8479 trie.prefix_set.insert(leaf1_path);
8481 trie.prefix_set.insert(leaf2_path);
8482
8483 let _root = trie.root();
8485 }
8486
8487 #[test]
8488 fn test_update_leaf_creates_embedded_nodes_then_root() {
8489 let mut leaf1_path_bytes = [0u8; 64];
8499 leaf1_path_bytes[63] = 1;
8500 let leaf1_path = Nibbles::from_nibbles(leaf1_path_bytes);
8501
8502 let mut leaf2_path_bytes = [0u8; 64];
8503 leaf2_path_bytes[63] = 2;
8504 let leaf2_path = Nibbles::from_nibbles(leaf2_path_bytes);
8505
8506 let mut trie = ParallelSparseTrie::default();
8508 trie.update_leaf(leaf1_path, vec![0x1]).unwrap();
8509 trie.update_leaf(leaf2_path, vec![0x2]).unwrap();
8510
8511 let _root = trie.root();
8513 }
8514}