1use crate::{
2 provider::{TrieNodeProvider, TrieNodeProviderFactory},
3 traits::SparseTrie as SparseTrieTrait,
4 ParallelSparseTrie, RevealableSparseTrie,
5};
6use alloc::{collections::VecDeque, vec::Vec};
7use alloy_primitives::{
8 map::{B256Map, B256Set, HashSet},
9 Bytes, B256,
10};
11use alloy_rlp::{Decodable, Encodable};
12use alloy_trie::proof::DecodedProofNodes;
13use reth_execution_errors::{SparseStateTrieErrorKind, SparseStateTrieResult, SparseTrieErrorKind};
14use reth_primitives_traits::Account;
15use reth_trie_common::{
16 proof::ProofNodes,
17 updates::{StorageTrieUpdates, TrieUpdates},
18 BranchNodeMasks, BranchNodeMasksMap, DecodedMultiProof, DecodedStorageMultiProof, MultiProof,
19 Nibbles, ProofTrieNode, RlpNode, StorageMultiProof, TrieAccount, TrieNode, EMPTY_ROOT_HASH,
20 TRIE_ACCOUNT_RLP_MAX_SIZE,
21};
22#[cfg(feature = "std")]
23use tracing::debug;
24use tracing::{instrument, trace};
25
26#[derive(Debug, Default)]
31pub struct DeferredDrops {
32 pub proof_nodes_bufs: Vec<Vec<ProofTrieNode>>,
34}
35
36#[derive(Debug)]
37pub struct SparseStateTrie<
39 A = ParallelSparseTrie, S = ParallelSparseTrie, > {
42 state: RevealableSparseTrie<A>,
44 revealed_account_paths: HashSet<Nibbles>,
46 storage: StorageTries<S>,
48 retain_updates: bool,
50 skip_proof_node_filtering: bool,
54 account_rlp_buf: Vec<u8>,
56 deferred_drops: DeferredDrops,
58 #[cfg(feature = "metrics")]
60 metrics: crate::metrics::SparseStateTrieMetrics,
61}
62
63impl<A, S> Default for SparseStateTrie<A, S>
64where
65 A: Default,
66 S: Default,
67{
68 fn default() -> Self {
69 Self {
70 state: Default::default(),
71 revealed_account_paths: Default::default(),
72 storage: Default::default(),
73 retain_updates: false,
74 skip_proof_node_filtering: false,
75 account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
76 deferred_drops: DeferredDrops::default(),
77 #[cfg(feature = "metrics")]
78 metrics: Default::default(),
79 }
80 }
81}
82
83#[cfg(test)]
84impl SparseStateTrie {
85 pub fn from_state(state: RevealableSparseTrie) -> Self {
87 Self { state, ..Default::default() }
88 }
89}
90
91impl<A, S> SparseStateTrie<A, S> {
92 pub const fn set_updates(&mut self, retain_updates: bool) {
94 self.retain_updates = retain_updates;
95 }
96
97 pub const fn with_updates(mut self, retain_updates: bool) -> Self {
99 self.set_updates(retain_updates);
100 self
101 }
102
103 pub fn set_accounts_trie(&mut self, trie: RevealableSparseTrie<A>) {
105 self.state = trie;
106 }
107
108 pub fn with_accounts_trie(mut self, trie: RevealableSparseTrie<A>) -> Self {
110 self.set_accounts_trie(trie);
111 self
112 }
113
114 pub fn set_default_storage_trie(&mut self, trie: RevealableSparseTrie<S>) {
117 self.storage.default_trie = trie;
118 }
119
120 pub fn with_default_storage_trie(mut self, trie: RevealableSparseTrie<S>) -> Self {
123 self.set_default_storage_trie(trie);
124 self
125 }
126
127 pub const fn with_skip_proof_node_filtering(mut self, skip: bool) -> Self {
133 self.skip_proof_node_filtering = skip;
134 self
135 }
136
137 pub fn take_deferred_drops(&mut self) -> DeferredDrops {
142 core::mem::take(&mut self.deferred_drops)
143 }
144}
145
146impl SparseStateTrie {
147 pub fn new() -> Self {
149 Self::default()
150 }
151}
152
153impl<A, S> SparseStateTrie<A, S>
154where
155 A: SparseTrieTrait + Default,
156 S: SparseTrieTrait + Default + Clone,
157{
158 pub const fn trie_mut(&mut self) -> &mut RevealableSparseTrie<A> {
160 &mut self.state
161 }
162
163 pub fn is_account_revealed(&self, account: B256) -> bool {
165 self.revealed_account_paths.contains(&Nibbles::unpack(account))
166 }
167
168 pub fn check_valid_account_witness(&self, address: B256) -> bool {
170 let path = Nibbles::unpack(address);
171 let trie = match self.state_trie_ref() {
172 Some(t) => t,
173 None => return false,
174 };
175
176 trie.find_leaf(&path, None).is_ok()
177 }
178
179 pub fn check_valid_storage_witness(&self, address: B256, slot: B256) -> bool {
181 let path = Nibbles::unpack(slot);
182 let trie = match self.storage_trie_ref(&address) {
183 Some(t) => t,
184 None => return false,
185 };
186
187 trie.find_leaf(&path, None).is_ok()
188 }
189
190 pub fn is_storage_slot_revealed(&self, account: B256, slot: B256) -> bool {
192 self.storage
193 .revealed_paths
194 .get(&account)
195 .is_some_and(|slots| slots.contains(&Nibbles::unpack(slot)))
196 }
197
198 pub fn get_account_value(&self, account: &B256) -> Option<&Vec<u8>> {
200 self.state.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(account))
201 }
202
203 pub fn get_storage_slot_value(&self, account: &B256, slot: &B256) -> Option<&Vec<u8>> {
205 self.storage.tries.get(account)?.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(slot))
206 }
207
208 pub const fn state_trie_ref(&self) -> Option<&A> {
210 self.state.as_revealed_ref()
211 }
212
213 pub fn storage_trie_ref(&self, address: &B256) -> Option<&S> {
215 self.storage.tries.get(address).and_then(|e| e.as_revealed_ref())
216 }
217
218 pub fn storage_trie_mut(&mut self, address: &B256) -> Option<&mut S> {
220 self.storage.tries.get_mut(address).and_then(|e| e.as_revealed_mut())
221 }
222
223 pub const fn storage_tries_mut(&mut self) -> &mut B256Map<RevealableSparseTrie<S>> {
225 &mut self.storage.tries
226 }
227
228 pub fn take_storage_trie(&mut self, address: &B256) -> Option<RevealableSparseTrie<S>> {
230 self.storage.tries.remove(address)
231 }
232
233 pub fn take_or_create_storage_trie(&mut self, address: &B256) -> RevealableSparseTrie<S> {
235 self.storage.tries.remove(address).unwrap_or_else(|| {
236 self.storage.cleared_tries.pop().unwrap_or_else(|| self.storage.default_trie.clone())
237 })
238 }
239
240 pub fn insert_storage_trie(&mut self, address: B256, storage_trie: RevealableSparseTrie<S>) {
242 self.storage.tries.insert(address, storage_trie);
243 }
244
245 pub fn get_or_create_storage_trie_mut(
247 &mut self,
248 address: B256,
249 ) -> &mut RevealableSparseTrie<S> {
250 self.storage.get_or_create_trie_mut(address)
251 }
252
253 pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
256 let decoded_multiproof = multiproof.try_into()?;
258
259 self.reveal_decoded_multiproof(decoded_multiproof)
261 }
262
263 #[instrument(
266 target = "trie::sparse",
267 skip_all,
268 fields(
269 account_nodes = multiproof.account_subtree.len(),
270 storages = multiproof.storages.len()
271 )
272 )]
273 pub fn reveal_decoded_multiproof(
274 &mut self,
275 multiproof: DecodedMultiProof,
276 ) -> SparseStateTrieResult<()> {
277 let DecodedMultiProof { account_subtree, storages, branch_node_masks } = multiproof;
278
279 self.reveal_decoded_account_multiproof(account_subtree, branch_node_masks)?;
281
282 #[cfg(not(feature = "std"))]
283 {
285 for (account, storage_subtree) in storages {
286 self.reveal_decoded_storage_multiproof(account, storage_subtree)?;
287 self.storage.modifications.mark_accessed(account);
289 }
290
291 Ok(())
292 }
293
294 #[cfg(feature = "std")]
295 {
297 use rayon::iter::ParallelIterator;
298 use reth_primitives_traits::ParallelBridgeBuffered;
299
300 let retain_updates = self.retain_updates;
301
302 let results: Vec<_> = storages
306 .into_iter()
307 .map(|(account, storage_subtree)| {
308 let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
309 let trie = self.storage.take_or_create_trie(&account);
310 (account, storage_subtree, revealed_nodes, trie)
311 })
312 .par_bridge_buffered()
313 .map(|(account, storage_subtree, mut revealed_nodes, mut trie)| {
314 let mut bufs = Vec::new();
315 let result = Self::reveal_decoded_storage_multiproof_inner(
316 account,
317 storage_subtree,
318 &mut revealed_nodes,
319 &mut trie,
320 &mut bufs,
321 retain_updates,
322 );
323
324 (account, revealed_nodes, trie, result, bufs)
325 })
326 .collect();
327
328 let mut any_err = Ok(());
331 for (account, revealed_nodes, trie, result, bufs) in results {
332 self.storage.revealed_paths.insert(account, revealed_nodes);
333 self.storage.tries.insert(account, trie);
334 self.storage.modifications.mark_accessed(account);
336 if let Ok(_metric_values) = result {
337 #[cfg(feature = "metrics")]
338 {
339 self.metrics
340 .increment_total_storage_nodes(_metric_values.total_nodes as u64);
341 self.metrics
342 .increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
343 }
344 } else {
345 any_err = result.map(|_| ());
346 }
347
348 self.deferred_drops.proof_nodes_bufs.extend(bufs);
350 }
351
352 any_err
353 }
354 }
355
356 #[instrument(
361 skip_all,
362 fields(
363 account_nodes = multiproof.account_proofs.len(),
364 storages = multiproof.storage_proofs.len()
365 )
366 )]
367 pub fn reveal_decoded_multiproof_v2(
368 &mut self,
369 multiproof: reth_trie_common::DecodedMultiProofV2,
370 ) -> SparseStateTrieResult<()> {
371 if !multiproof.account_proofs.is_empty() {
379 self.reveal_account_v2_proof_nodes(multiproof.account_proofs)?;
380 }
381
382 #[cfg(not(feature = "std"))]
383 {
385 for (account, storage_proofs) in multiproof.storage_proofs {
386 self.reveal_storage_v2_proof_nodes(account, storage_proofs)?;
387 self.storage.modifications.mark_accessed(account);
389 }
390
391 Ok(())
392 }
393
394 #[cfg(feature = "std")]
395 {
397 use rayon::iter::ParallelIterator;
398 use reth_primitives_traits::ParallelBridgeBuffered;
399
400 let retain_updates = self.retain_updates;
401 let skip_filtering = self.skip_proof_node_filtering;
402
403 let results: Vec<_> = multiproof
407 .storage_proofs
408 .into_iter()
409 .map(|(account, storage_proofs)| {
410 let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
411 let trie = self.storage.take_or_create_trie(&account);
412 (account, storage_proofs, revealed_nodes, trie)
413 })
414 .par_bridge_buffered()
415 .map(|(account, storage_proofs, mut revealed_nodes, mut trie)| {
416 let mut bufs = Vec::new();
417 let result = Self::reveal_storage_v2_proof_nodes_inner(
418 account,
419 storage_proofs,
420 &mut revealed_nodes,
421 &mut trie,
422 &mut bufs,
423 retain_updates,
424 skip_filtering,
425 );
426 (account, result, revealed_nodes, trie, bufs)
427 })
428 .collect();
429
430 let mut any_err = Ok(());
431 for (account, result, revealed_nodes, trie, bufs) in results {
432 self.storage.revealed_paths.insert(account, revealed_nodes);
433 self.storage.tries.insert(account, trie);
434 self.storage.modifications.mark_accessed(account);
436 if let Ok(_metric_values) = result {
437 #[cfg(feature = "metrics")]
438 {
439 self.metrics
440 .increment_total_storage_nodes(_metric_values.total_nodes as u64);
441 self.metrics
442 .increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
443 }
444 } else {
445 any_err = result.map(|_| ());
446 }
447
448 self.deferred_drops.proof_nodes_bufs.extend(bufs);
450 }
451
452 any_err
453 }
454 }
455
456 pub fn reveal_account_multiproof(
458 &mut self,
459 account_subtree: ProofNodes,
460 branch_node_masks: BranchNodeMasksMap,
461 ) -> SparseStateTrieResult<()> {
462 let decoded_multiproof = account_subtree.try_into()?;
464 self.reveal_decoded_account_multiproof(decoded_multiproof, branch_node_masks)
465 }
466
467 pub fn reveal_decoded_account_multiproof(
469 &mut self,
470 account_subtree: DecodedProofNodes,
471 branch_node_masks: BranchNodeMasksMap,
472 ) -> SparseStateTrieResult<()> {
473 let FilterMappedProofNodes {
474 root_node,
475 mut nodes,
476 new_nodes,
477 metric_values: _metric_values,
478 } = filter_map_revealed_nodes(
479 account_subtree,
480 &mut self.revealed_account_paths,
481 &branch_node_masks,
482 )?;
483 #[cfg(feature = "metrics")]
484 {
485 self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
486 self.metrics.increment_skipped_account_nodes(_metric_values.skipped_nodes as u64);
487 }
488
489 if let Some(root_node) = root_node {
490 trace!(target: "trie::sparse", ?root_node, "Revealing root account node");
492 let trie =
493 self.state.reveal_root(root_node.node, root_node.masks, self.retain_updates)?;
494
495 trie.reserve_nodes(new_nodes);
498
499 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes");
500 trie.reveal_nodes(&mut nodes)?;
501 }
502
503 self.deferred_drops.proof_nodes_bufs.push(nodes);
505
506 Ok(())
507 }
508
509 pub fn reveal_account_v2_proof_nodes(
514 &mut self,
515 mut nodes: Vec<ProofTrieNode>,
516 ) -> SparseStateTrieResult<()> {
517 if self.skip_proof_node_filtering {
518 let capacity = estimate_v2_proof_capacity(&nodes);
519
520 #[cfg(feature = "metrics")]
521 self.metrics.increment_total_account_nodes(nodes.len() as u64);
522
523 let root_node = nodes.iter().find(|n| n.path.is_empty());
524 let trie = if let Some(root_node) = root_node {
525 trace!(target: "trie::sparse", ?root_node, "Revealing root account node from V2 proof");
526 self.state.reveal_root(
527 root_node.node.clone(),
528 root_node.masks,
529 self.retain_updates,
530 )?
531 } else {
532 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?
533 };
534 trie.reserve_nodes(capacity);
535 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes from V2 proof (unfiltered)");
536 trie.reveal_nodes(&mut nodes)?;
537
538 self.deferred_drops.proof_nodes_bufs.push(nodes);
539 return Ok(())
540 }
541
542 let FilteredV2ProofNodes { root_node, mut nodes, new_nodes, metric_values: _metric_values } =
543 filter_revealed_v2_proof_nodes(nodes, &mut self.revealed_account_paths)?;
544
545 #[cfg(feature = "metrics")]
546 {
547 self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
548 self.metrics.increment_skipped_account_nodes(_metric_values.skipped_nodes as u64);
549 }
550
551 let trie = if let Some(root_node) = root_node {
552 trace!(target: "trie::sparse", ?root_node, "Revealing root account node from V2 proof");
553 self.state.reveal_root(root_node.node, root_node.masks, self.retain_updates)?
554 } else {
555 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?
556 };
557
558 trie.reserve_nodes(new_nodes);
559
560 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes from V2 proof");
561 trie.reveal_nodes(&mut nodes)?;
562
563 self.deferred_drops.proof_nodes_bufs.push(nodes);
565
566 Ok(())
567 }
568
569 pub fn reveal_storage_v2_proof_nodes(
574 &mut self,
575 account: B256,
576 nodes: Vec<ProofTrieNode>,
577 ) -> SparseStateTrieResult<()> {
578 let (trie, revealed_paths) = self.storage.get_trie_and_revealed_paths_mut(account);
579 let _metric_values = Self::reveal_storage_v2_proof_nodes_inner(
580 account,
581 nodes,
582 revealed_paths,
583 trie,
584 &mut self.deferred_drops.proof_nodes_bufs,
585 self.retain_updates,
586 self.skip_proof_node_filtering,
587 )?;
588
589 #[cfg(feature = "metrics")]
590 {
591 self.metrics.increment_total_storage_nodes(_metric_values.total_nodes as u64);
592 self.metrics.increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
593 }
594
595 Ok(())
596 }
597
598 fn reveal_storage_v2_proof_nodes_inner(
601 account: B256,
602 mut nodes: Vec<ProofTrieNode>,
603 revealed_nodes: &mut HashSet<Nibbles>,
604 trie: &mut RevealableSparseTrie<S>,
605 bufs: &mut Vec<Vec<ProofTrieNode>>,
606 retain_updates: bool,
607 skip_filtering: bool,
608 ) -> SparseStateTrieResult<ProofNodesMetricValues> {
609 if skip_filtering {
610 let capacity = estimate_v2_proof_capacity(&nodes);
611 let metric_values =
612 ProofNodesMetricValues { total_nodes: nodes.len(), skipped_nodes: 0 };
613
614 let root_node = nodes.iter().find(|n| n.path.is_empty());
615 let trie = if let Some(root_node) = root_node {
616 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node from V2 proof");
617 trie.reveal_root(root_node.node.clone(), root_node.masks, retain_updates)?
618 } else {
619 trie.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?
620 };
621 trie.reserve_nodes(capacity);
622 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes from V2 proof (unfiltered)");
623 trie.reveal_nodes(&mut nodes)?;
624
625 bufs.push(nodes);
626 return Ok(metric_values)
627 }
628
629 let FilteredV2ProofNodes { root_node, mut nodes, new_nodes, metric_values } =
630 filter_revealed_v2_proof_nodes(nodes, revealed_nodes)?;
631
632 let trie = if let Some(root_node) = root_node {
633 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node from V2 proof");
634 trie.reveal_root(root_node.node, root_node.masks, retain_updates)?
635 } else {
636 trie.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?
637 };
638
639 trie.reserve_nodes(new_nodes);
640
641 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes from V2 proof");
642 trie.reveal_nodes(&mut nodes)?;
643
644 bufs.push(nodes);
646
647 Ok(metric_values)
648 }
649
650 pub fn reveal_storage_multiproof(
652 &mut self,
653 account: B256,
654 storage_subtree: StorageMultiProof,
655 ) -> SparseStateTrieResult<()> {
656 let decoded_multiproof = storage_subtree.try_into()?;
658 self.reveal_decoded_storage_multiproof(account, decoded_multiproof)
659 }
660
661 pub fn reveal_decoded_storage_multiproof(
663 &mut self,
664 account: B256,
665 storage_subtree: DecodedStorageMultiProof,
666 ) -> SparseStateTrieResult<()> {
667 let (trie, revealed_paths) = self.storage.get_trie_and_revealed_paths_mut(account);
668 let _metric_values = Self::reveal_decoded_storage_multiproof_inner(
669 account,
670 storage_subtree,
671 revealed_paths,
672 trie,
673 &mut self.deferred_drops.proof_nodes_bufs,
674 self.retain_updates,
675 )?;
676
677 #[cfg(feature = "metrics")]
678 {
679 self.metrics.increment_total_storage_nodes(_metric_values.total_nodes as u64);
680 self.metrics.increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
681 }
682
683 Ok(())
684 }
685
686 fn reveal_decoded_storage_multiproof_inner(
689 account: B256,
690 storage_subtree: DecodedStorageMultiProof,
691 revealed_nodes: &mut HashSet<Nibbles>,
692 trie: &mut RevealableSparseTrie<S>,
693 bufs: &mut Vec<Vec<ProofTrieNode>>,
694 retain_updates: bool,
695 ) -> SparseStateTrieResult<ProofNodesMetricValues> {
696 let FilterMappedProofNodes { root_node, mut nodes, new_nodes, metric_values } =
697 filter_map_revealed_nodes(
698 storage_subtree.subtree,
699 revealed_nodes,
700 &storage_subtree.branch_node_masks,
701 )?;
702
703 if let Some(root_node) = root_node {
704 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node");
706 let trie = trie.reveal_root(root_node.node, root_node.masks, retain_updates)?;
707
708 trie.reserve_nodes(new_nodes);
711
712 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes");
713 trie.reveal_nodes(&mut nodes)?;
714 }
715
716 bufs.push(nodes);
718
719 Ok(metric_values)
720 }
721
722 pub fn reveal_witness(
726 &mut self,
727 state_root: B256,
728 witness: &B256Map<Bytes>,
729 ) -> SparseStateTrieResult<()> {
730 let mut queue = VecDeque::from([(state_root, Nibbles::default(), None)]);
733
734 while let Some((hash, path, maybe_account)) = queue.pop_front() {
735 let Some(trie_node_bytes) = witness.get(&hash) else { continue };
737 let trie_node = TrieNode::decode(&mut &trie_node_bytes[..])?;
738
739 match &trie_node {
741 TrieNode::Branch(branch) => {
742 for (idx, maybe_child) in branch.as_ref().children() {
743 if let Some(child_hash) = maybe_child.and_then(RlpNode::as_hash) {
744 let mut child_path = path;
745 child_path.push_unchecked(idx);
746 queue.push_back((child_hash, child_path, maybe_account));
747 }
748 }
749 }
750 TrieNode::Extension(ext) => {
751 if let Some(child_hash) = ext.child.as_hash() {
752 let mut child_path = path;
753 child_path.extend(&ext.key);
754 queue.push_back((child_hash, child_path, maybe_account));
755 }
756 }
757 TrieNode::Leaf(leaf) => {
758 let mut full_path = path;
759 full_path.extend(&leaf.key);
760 if maybe_account.is_none() {
761 let hashed_address = B256::from_slice(&full_path.pack());
762 let account = TrieAccount::decode(&mut &leaf.value[..])?;
763 if account.storage_root != EMPTY_ROOT_HASH {
764 queue.push_back((
765 account.storage_root,
766 Nibbles::default(),
767 Some(hashed_address),
768 ));
769 }
770 }
771 }
772 TrieNode::EmptyRoot => {} };
774
775 if let Some(account) = maybe_account {
777 if self
779 .storage
780 .revealed_paths
781 .get(&account)
782 .is_none_or(|paths| !paths.contains(&path))
783 {
784 let retain_updates = self.retain_updates;
785 let (storage_trie_entry, revealed_storage_paths) =
786 self.storage.get_trie_and_revealed_paths_mut(account);
787
788 if path.is_empty() {
789 storage_trie_entry.reveal_root(trie_node, None, retain_updates)?;
791 } else {
792 storage_trie_entry
794 .as_revealed_mut()
795 .ok_or(SparseTrieErrorKind::Blind)?
796 .reveal_node(path, trie_node, None)?;
797 }
798
799 revealed_storage_paths.insert(path);
801 }
802 }
803 else if !self.revealed_account_paths.contains(&path) {
805 if path.is_empty() {
806 self.state.reveal_root(trie_node, None, self.retain_updates)?;
808 } else {
809 self.state
811 .as_revealed_mut()
812 .ok_or(SparseTrieErrorKind::Blind)?
813 .reveal_node(path, trie_node, None)?;
814 }
815
816 self.revealed_account_paths.insert(path);
818 }
819 }
820
821 Ok(())
822 }
823
824 pub fn wipe_storage(&mut self, address: B256) -> SparseStateTrieResult<()> {
826 if let Some(trie) = self.storage.tries.get_mut(&address) {
827 trie.wipe()?;
828 }
829 Ok(())
830 }
831
832 #[instrument(target = "trie::sparse", skip_all)]
836 pub fn calculate_subtries(&mut self) {
837 if let RevealableSparseTrie::Revealed(trie) = &mut self.state {
838 trie.update_subtrie_hashes();
839 }
840 }
841
842 pub fn storage_root(&mut self, account: &B256) -> Option<B256> {
844 self.storage.tries.get_mut(account).and_then(|trie| trie.root())
845 }
846
847 fn revealed_trie_mut(
851 &mut self,
852 provider_factory: impl TrieNodeProviderFactory,
853 ) -> SparseStateTrieResult<&mut A> {
854 match self.state {
855 RevealableSparseTrie::Blind(_) => {
856 let (root_node, hash_mask, tree_mask) = provider_factory
857 .account_node_provider()
858 .trie_node(&Nibbles::default())?
859 .map(|node| {
860 TrieNode::decode(&mut &node.node[..])
861 .map(|decoded| (decoded, node.hash_mask, node.tree_mask))
862 })
863 .transpose()?
864 .unwrap_or((TrieNode::EmptyRoot, None, None));
865 let masks = BranchNodeMasks::from_optional(hash_mask, tree_mask);
866 self.state.reveal_root(root_node, masks, self.retain_updates).map_err(Into::into)
867 }
868 RevealableSparseTrie::Revealed(ref mut trie) => Ok(trie),
869 }
870 }
871
872 pub fn root(
876 &mut self,
877 provider_factory: impl TrieNodeProviderFactory,
878 ) -> SparseStateTrieResult<B256> {
879 #[cfg(feature = "metrics")]
881 self.metrics.record();
882
883 Ok(self.revealed_trie_mut(provider_factory)?.root())
884 }
885
886 #[instrument(target = "trie::sparse", skip_all)]
888 pub fn root_with_updates(
889 &mut self,
890 provider_factory: impl TrieNodeProviderFactory,
891 ) -> SparseStateTrieResult<(B256, TrieUpdates)> {
892 #[cfg(feature = "metrics")]
894 self.metrics.record();
895
896 let storage_tries = self.storage_trie_updates();
897 let revealed = self.revealed_trie_mut(provider_factory)?;
898
899 let (root, updates) = (revealed.root(), revealed.take_updates());
900 let updates = TrieUpdates {
901 account_nodes: updates.updated_nodes,
902 removed_nodes: updates.removed_nodes,
903 storage_tries,
904 };
905 Ok((root, updates))
906 }
907
908 pub fn storage_trie_updates(&mut self) -> B256Map<StorageTrieUpdates> {
912 self.storage
913 .tries
914 .iter_mut()
915 .map(|(address, trie)| {
916 let trie = trie.as_revealed_mut().unwrap();
917 let updates = trie.take_updates();
918 let updates = StorageTrieUpdates {
919 is_deleted: updates.wiped,
920 storage_nodes: updates.updated_nodes,
921 removed_nodes: updates.removed_nodes,
922 };
923 (*address, updates)
924 })
925 .filter(|(_, updates)| !updates.is_empty())
926 .collect()
927 }
928
929 pub fn take_trie_updates(&mut self) -> Option<TrieUpdates> {
933 let storage_tries = self.storage_trie_updates();
934 self.state.as_revealed_mut().map(|state| {
935 let updates = state.take_updates();
936 TrieUpdates {
937 account_nodes: updates.updated_nodes,
938 removed_nodes: updates.removed_nodes,
939 storage_tries,
940 }
941 })
942 }
943
944 pub fn update_account_leaf(
946 &mut self,
947 path: Nibbles,
948 value: Vec<u8>,
949 provider_factory: impl TrieNodeProviderFactory,
950 ) -> SparseStateTrieResult<()> {
951 if !self.revealed_account_paths.contains(&path) {
952 self.revealed_account_paths.insert(path);
953 }
954
955 let provider = provider_factory.account_node_provider();
956 self.state.update_leaf(path, value, provider)?;
957 Ok(())
958 }
959
960 pub fn update_storage_leaf(
962 &mut self,
963 address: B256,
964 slot: Nibbles,
965 value: Vec<u8>,
966 provider_factory: impl TrieNodeProviderFactory,
967 ) -> SparseStateTrieResult<()> {
968 let provider = provider_factory.storage_node_provider(address);
969 self.storage
970 .tries
971 .get_mut(&address)
972 .ok_or(SparseTrieErrorKind::Blind)?
973 .update_leaf(slot, value, provider)?;
974 self.storage.get_revealed_paths_mut(address).insert(slot);
975 Ok(())
976 }
977
978 #[instrument(level = "trace", target = "trie::sparse", skip_all)]
984 pub fn update_account(
985 &mut self,
986 address: B256,
987 account: Account,
988 provider_factory: impl TrieNodeProviderFactory,
989 ) -> SparseStateTrieResult<bool> {
990 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
991 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
992 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
993 } else if self.is_account_revealed(address) {
994 trace!(target: "trie::sparse", ?address, "Retrieving storage root from account leaf to update account");
995 if let Some(value) = self.get_account_value(&address) {
997 TrieAccount::decode(&mut &value[..])?.storage_root
999 } else {
1000 EMPTY_ROOT_HASH
1002 }
1003 } else {
1004 return Err(SparseTrieErrorKind::Blind.into())
1005 };
1006
1007 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
1008 return Ok(false);
1009 }
1010
1011 trace!(target: "trie::sparse", ?address, "Updating account");
1012 let nibbles = Nibbles::unpack(address);
1013 self.account_rlp_buf.clear();
1014 account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
1015 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
1016
1017 Ok(true)
1018 }
1019
1020 #[instrument(target = "trie::sparse", skip_all)]
1027 pub fn update_account_storage_root(
1028 &mut self,
1029 address: B256,
1030 provider_factory: impl TrieNodeProviderFactory,
1031 ) -> SparseStateTrieResult<bool> {
1032 if !self.is_account_revealed(address) {
1033 return Err(SparseTrieErrorKind::Blind.into())
1034 }
1035
1036 let Some(mut trie_account) = self
1038 .get_account_value(&address)
1039 .map(|v| TrieAccount::decode(&mut &v[..]))
1040 .transpose()?
1041 else {
1042 trace!(target: "trie::sparse", ?address, "Account not found in trie, skipping storage root update");
1043 return Ok(true)
1044 };
1045
1046 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
1049 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
1050 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
1051 } else {
1052 EMPTY_ROOT_HASH
1053 };
1054
1055 trie_account.storage_root = storage_root;
1057
1058 if trie_account == TrieAccount::default() {
1060 return Ok(false)
1061 }
1062
1063 trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
1065 let nibbles = Nibbles::unpack(address);
1066 self.account_rlp_buf.clear();
1067 trie_account.encode(&mut self.account_rlp_buf);
1068 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
1069
1070 Ok(true)
1071 }
1072
1073 #[instrument(target = "trie::sparse", skip_all)]
1075 pub fn remove_account_leaf(
1076 &mut self,
1077 path: &Nibbles,
1078 provider_factory: impl TrieNodeProviderFactory,
1079 ) -> SparseStateTrieResult<()> {
1080 let provider = provider_factory.account_node_provider();
1081 self.state.remove_leaf(path, provider)?;
1082 Ok(())
1083 }
1084
1085 pub fn remove_storage_leaf(
1087 &mut self,
1088 address: B256,
1089 slot: &Nibbles,
1090 provider_factory: impl TrieNodeProviderFactory,
1091 ) -> SparseStateTrieResult<()> {
1092 let storage_trie =
1093 self.storage.tries.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
1094
1095 let provider = provider_factory.storage_node_provider(address);
1096 storage_trie.remove_leaf(slot, provider)?;
1097 Ok(())
1098 }
1099}
1100
1101impl<A, S> SparseStateTrie<A, S>
1102where
1103 A: SparseTrieTrait + Default,
1104 S: SparseTrieTrait + Default + Clone,
1105{
1106 pub fn clear(&mut self) {
1111 self.state.clear();
1112 self.revealed_account_paths.clear();
1113 self.storage.clear();
1114 self.account_rlp_buf.clear();
1115 }
1116
1117 pub fn shrink_to(&mut self, max_nodes: usize, max_values: usize) {
1122 let storage_tries_count = self.storage.tries.len() + self.storage.cleared_tries.len();
1124
1125 let total_tries = 1 + storage_tries_count;
1127
1128 let nodes_per_trie = max_nodes / total_tries;
1130 let values_per_trie = max_values / total_tries;
1131
1132 self.state.shrink_nodes_to(nodes_per_trie);
1134 self.state.shrink_values_to(values_per_trie);
1135
1136 let storage_nodes = max_nodes.saturating_sub(nodes_per_trie);
1138 let storage_values = max_values.saturating_sub(values_per_trie);
1139
1140 self.storage.shrink_to(storage_nodes, storage_values);
1142 }
1143
1144 #[cfg(feature = "std")]
1158 #[instrument(
1159 name = "SparseStateTrie::prune",
1160 target = "trie::sparse",
1161 skip_all,
1162 fields(max_depth, max_storage_tries)
1163 )]
1164 pub fn prune(&mut self, max_depth: usize, max_storage_tries: usize) {
1165 rayon::join(
1167 || {
1168 if let Some(trie) = self.state.as_revealed_mut() {
1169 trie.prune(max_depth);
1170 }
1171 self.revealed_account_paths.clear();
1172 },
1173 || {
1174 self.storage.prune(max_depth, max_storage_tries);
1175 },
1176 );
1177 }
1178}
1179
1180#[derive(Debug, Default)]
1184struct StorageTries<S = ParallelSparseTrie> {
1185 tries: B256Map<RevealableSparseTrie<S>>,
1187 cleared_tries: Vec<RevealableSparseTrie<S>>,
1189 revealed_paths: B256Map<HashSet<Nibbles>>,
1191 cleared_revealed_paths: Vec<HashSet<Nibbles>>,
1193 default_trie: RevealableSparseTrie<S>,
1195 modifications: StorageTrieModifications,
1197}
1198
1199#[cfg(feature = "std")]
1200impl<S: SparseTrieTrait> StorageTries<S> {
1201 fn prune(&mut self, max_depth: usize, max_storage_tries: usize) {
1206 let fn_start = std::time::Instant::now();
1207 let mut stats =
1208 StorageTriesPruneStats { total_tries_before: self.tries.len(), ..Default::default() };
1209
1210 self.modifications.update_and_reset();
1212
1213 let mut trie_info: Vec<(B256, usize, usize)> = self
1217 .tries
1218 .iter()
1219 .map(|(address, trie)| {
1220 let size = match trie {
1221 RevealableSparseTrie::Blind(_) => return (*address, 0, 0),
1222 RevealableSparseTrie::Revealed(t) => t.size_hint(),
1223 };
1224 let heat = self.modifications.heat(address);
1225 let heat_multiplier = 1 + (heat.min(4) / 2) as usize;
1227 (*address, size, size * heat_multiplier)
1228 })
1229 .collect();
1230
1231 if trie_info.len() > max_storage_tries {
1233 trie_info
1234 .select_nth_unstable_by(max_storage_tries.saturating_sub(1), |a, b| b.2.cmp(&a.2));
1235 trie_info.truncate(max_storage_tries);
1236 }
1237 let tries_to_keep: B256Map<usize> =
1238 trie_info.iter().map(|(address, size, _)| (*address, *size)).collect();
1239 stats.tries_to_keep = tries_to_keep.len();
1240
1241 let tries_to_clear: Vec<B256> =
1243 self.tries.keys().filter(|addr| !tries_to_keep.contains_key(*addr)).copied().collect();
1244 stats.tries_to_evict = tries_to_clear.len();
1245
1246 for address in &tries_to_clear {
1248 if let Some(mut trie) = self.tries.remove(address) {
1249 trie.clear();
1250 self.cleared_tries.push(trie);
1251 }
1252 if let Some(mut paths) = self.revealed_paths.remove(address) {
1253 paths.clear();
1254 self.cleared_revealed_paths.push(paths);
1255 }
1256 self.modifications.remove(address);
1257 }
1258
1259 const MIN_SIZE_TO_PRUNE: usize = 1000;
1263 let prune_start = std::time::Instant::now();
1264 for (address, size) in &tries_to_keep {
1265 if *size < MIN_SIZE_TO_PRUNE {
1266 stats.skipped_small += 1;
1267 continue; }
1269 let Some(heat_state) = self.modifications.get_mut(address) else {
1270 continue; };
1272 if heat_state.prune_backlog < 2 {
1274 stats.skipped_recently_pruned += 1;
1275 continue; }
1277 if let Some(trie) = self.tries.get_mut(address).and_then(|t| t.as_revealed_mut()) {
1278 trie.prune(max_depth);
1279 heat_state.prune_backlog = 0; stats.pruned_count += 1;
1281 }
1282 }
1283 stats.prune_elapsed = prune_start.elapsed();
1284
1285 for hash in tries_to_keep.keys() {
1287 if let Some(paths) = self.revealed_paths.get_mut(hash) {
1288 paths.clear();
1289 }
1290 }
1291
1292 stats.total_tries_after = self.tries.len();
1293 stats.total_elapsed = fn_start.elapsed();
1294
1295 debug!(
1296 target: "trie::sparse",
1297 before = stats.total_tries_before,
1298 after = stats.total_tries_after,
1299 kept = stats.tries_to_keep,
1300 evicted = stats.tries_to_evict,
1301 pruned = stats.pruned_count,
1302 skipped_small = stats.skipped_small,
1303 skipped_recent = stats.skipped_recently_pruned,
1304 ?stats.prune_elapsed,
1305 ?stats.total_elapsed,
1306 "StorageTries::prune completed"
1307 );
1308 }
1309}
1310
1311impl<S: SparseTrieTrait> StorageTries<S> {
1312 fn clear(&mut self) {
1315 self.cleared_tries.extend(self.tries.drain().map(|(_, mut trie)| {
1316 trie.clear();
1317 trie
1318 }));
1319 self.cleared_revealed_paths.extend(self.revealed_paths.drain().map(|(_, mut set)| {
1320 set.clear();
1321 set
1322 }));
1323 self.modifications.clear();
1324 }
1325
1326 fn shrink_to(&mut self, max_nodes: usize, max_values: usize) {
1330 let total_tries = self.tries.len() + self.cleared_tries.len();
1331 if total_tries == 0 {
1332 return;
1333 }
1334
1335 let nodes_per_trie = max_nodes / total_tries;
1337 let values_per_trie = max_values / total_tries;
1338
1339 for trie in self.tries.values_mut() {
1341 trie.shrink_nodes_to(nodes_per_trie);
1342 trie.shrink_values_to(values_per_trie);
1343 }
1344
1345 for trie in &mut self.cleared_tries {
1347 trie.shrink_nodes_to(nodes_per_trie);
1348 trie.shrink_values_to(values_per_trie);
1349 }
1350 }
1351}
1352
1353impl<S: SparseTrieTrait + Clone> StorageTries<S> {
1354 fn get_revealed_paths_mut(&mut self, account: B256) -> &mut HashSet<Nibbles> {
1357 self.revealed_paths
1358 .entry(account)
1359 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default())
1360 }
1361
1362 fn get_trie_and_revealed_paths_mut(
1365 &mut self,
1366 account: B256,
1367 ) -> (&mut RevealableSparseTrie<S>, &mut HashSet<Nibbles>) {
1368 let trie = self.tries.entry(account).or_insert_with(|| {
1369 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
1370 });
1371
1372 let revealed_paths = self
1373 .revealed_paths
1374 .entry(account)
1375 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default());
1376
1377 (trie, revealed_paths)
1378 }
1379
1380 fn get_or_create_trie_mut(&mut self, address: B256) -> &mut RevealableSparseTrie<S> {
1382 self.tries.entry(address).or_insert_with(|| {
1383 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
1384 })
1385 }
1386
1387 #[cfg(feature = "std")]
1390 fn take_or_create_trie(&mut self, account: &B256) -> RevealableSparseTrie<S> {
1391 self.tries.remove(account).unwrap_or_else(|| {
1392 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
1393 })
1394 }
1395
1396 #[cfg(feature = "std")]
1399 fn take_or_create_revealed_paths(&mut self, account: &B256) -> HashSet<Nibbles> {
1400 self.revealed_paths
1401 .remove(account)
1402 .unwrap_or_else(|| self.cleared_revealed_paths.pop().unwrap_or_default())
1403 }
1404}
1405
1406#[derive(Debug, Default)]
1408#[allow(dead_code)]
1409struct StorageTriesPruneStats {
1410 total_tries_before: usize,
1411 total_tries_after: usize,
1412 tries_to_keep: usize,
1413 tries_to_evict: usize,
1414 pruned_count: usize,
1415 skipped_small: usize,
1416 skipped_recently_pruned: usize,
1417 prune_elapsed: core::time::Duration,
1418 total_elapsed: core::time::Duration,
1419}
1420
1421#[derive(Debug, Clone, Copy, Default)]
1426#[allow(dead_code)]
1427struct TrieModificationState {
1428 heat: u8,
1431 prune_backlog: u8,
1434}
1435
1436#[derive(Debug, Default)]
1445struct StorageTrieModifications {
1446 state: B256Map<TrieModificationState>,
1448 accessed_this_cycle: B256Set,
1450}
1451
1452#[allow(dead_code)]
1453impl StorageTrieModifications {
1454 #[inline]
1457 fn mark_accessed(&mut self, address: B256) {
1458 self.accessed_this_cycle.insert(address);
1459 }
1460
1461 #[inline]
1463 fn get_mut(&mut self, address: &B256) -> Option<&mut TrieModificationState> {
1464 self.state.get_mut(address)
1465 }
1466
1467 #[inline]
1469 fn heat(&self, address: &B256) -> u8 {
1470 self.state.get(address).map_or(0, |s| s.heat)
1471 }
1472
1473 fn update_and_reset(&mut self) {
1476 for address in self.accessed_this_cycle.drain() {
1477 let entry = self.state.entry(address).or_default();
1478 entry.heat = entry.heat.saturating_add(1);
1479 entry.prune_backlog = entry.prune_backlog.saturating_add(1);
1480 }
1481 }
1482
1483 fn remove(&mut self, address: &B256) {
1485 self.state.remove(address);
1486 self.accessed_this_cycle.remove(address);
1487 }
1488
1489 fn clear(&mut self) {
1491 self.state.clear();
1492 self.accessed_this_cycle.clear();
1493 }
1494}
1495
1496#[derive(Debug, PartialEq, Eq, Default)]
1497struct ProofNodesMetricValues {
1498 total_nodes: usize,
1500 skipped_nodes: usize,
1502}
1503
1504#[derive(Debug, PartialEq, Eq)]
1506struct FilterMappedProofNodes {
1507 root_node: Option<ProofTrieNode>,
1509 nodes: Vec<ProofTrieNode>,
1511 new_nodes: usize,
1514 metric_values: ProofNodesMetricValues,
1516}
1517
1518fn filter_map_revealed_nodes(
1522 proof_nodes: DecodedProofNodes,
1523 revealed_nodes: &mut HashSet<Nibbles>,
1524 branch_node_masks: &BranchNodeMasksMap,
1525) -> SparseStateTrieResult<FilterMappedProofNodes> {
1526 let mut result = FilterMappedProofNodes {
1527 root_node: None,
1528 nodes: Vec::with_capacity(proof_nodes.len()),
1529 new_nodes: 0,
1530 metric_values: Default::default(),
1531 };
1532
1533 let proof_nodes_len = proof_nodes.len();
1534 for (path, proof_node) in proof_nodes.into_inner() {
1535 result.metric_values.total_nodes += 1;
1536
1537 let is_root = path.is_empty();
1538
1539 if !is_root && !revealed_nodes.insert(path) {
1542 result.metric_values.skipped_nodes += 1;
1543 continue
1544 }
1545
1546 result.new_nodes += 1;
1547
1548 let masks = match &proof_node {
1551 TrieNode::Branch(branch) => {
1552 result.new_nodes += branch.state_mask.count_ones() as usize;
1555 branch_node_masks.get(&path).copied()
1556 }
1557 TrieNode::Extension(_) => {
1558 result.new_nodes += 1;
1560 None
1561 }
1562 _ => None,
1563 };
1564
1565 let node = ProofTrieNode { path, node: proof_node, masks };
1566
1567 if is_root {
1568 if matches!(node.node, TrieNode::EmptyRoot) && proof_nodes_len > 1 {
1570 return Err(SparseStateTrieErrorKind::InvalidRootNode {
1571 path,
1572 node: alloy_rlp::encode(&node.node).into(),
1573 }
1574 .into())
1575 }
1576
1577 result.root_node = Some(node);
1578
1579 continue
1580 }
1581
1582 result.nodes.push(node);
1583 }
1584
1585 Ok(result)
1586}
1587
1588#[derive(Debug, PartialEq, Eq)]
1590struct FilteredV2ProofNodes {
1591 root_node: Option<ProofTrieNode>,
1593 nodes: Vec<ProofTrieNode>,
1595 new_nodes: usize,
1598 metric_values: ProofNodesMetricValues,
1600}
1601
1602fn estimate_v2_proof_capacity(nodes: &[ProofTrieNode]) -> usize {
1608 let mut capacity = nodes.len();
1609
1610 for node in nodes {
1611 match &node.node {
1612 TrieNode::Branch(branch) => {
1613 capacity += branch.state_mask.count_ones() as usize;
1614 }
1615 TrieNode::Extension(_) => {
1616 capacity += 1;
1617 }
1618 _ => {}
1619 };
1620 }
1621
1622 capacity
1623}
1624
1625fn filter_revealed_v2_proof_nodes(
1631 proof_nodes: Vec<ProofTrieNode>,
1632 revealed_nodes: &mut HashSet<Nibbles>,
1633) -> SparseStateTrieResult<FilteredV2ProofNodes> {
1634 let mut result = FilteredV2ProofNodes {
1635 root_node: None,
1636 nodes: Vec::with_capacity(proof_nodes.len()),
1637 new_nodes: 0,
1638 metric_values: Default::default(),
1639 };
1640
1641 let non_empty_root_count =
1645 proof_nodes.iter().filter(|n| !matches!(n.node, TrieNode::EmptyRoot)).count();
1646
1647 for node in proof_nodes {
1648 result.metric_values.total_nodes += 1;
1649
1650 let is_root = node.path.is_empty();
1651
1652 if !is_root && !revealed_nodes.insert(node.path) {
1655 result.metric_values.skipped_nodes += 1;
1656 continue
1657 }
1658
1659 result.new_nodes += 1;
1660
1661 match &node.node {
1663 TrieNode::Branch(branch) => {
1664 result.new_nodes += branch.state_mask.count_ones() as usize;
1665 }
1666 TrieNode::Extension(_) => {
1667 result.new_nodes += 1;
1668 }
1669 _ => {}
1670 };
1671
1672 if is_root {
1673 if matches!(node.node, TrieNode::EmptyRoot) && non_empty_root_count > 0 {
1675 return Err(SparseStateTrieErrorKind::InvalidRootNode {
1676 path: node.path,
1677 node: alloy_rlp::encode(&node.node).into(),
1678 }
1679 .into())
1680 }
1681
1682 result.root_node = Some(node);
1683 continue
1684 }
1685
1686 result.nodes.push(node);
1687 }
1688
1689 Ok(result)
1690}
1691
1692#[cfg(test)]
1693mod tests {
1694 use super::*;
1695 use crate::{provider::DefaultTrieNodeProviderFactory, LeafLookup, ParallelSparseTrie};
1696 use alloy_primitives::{
1697 b256,
1698 map::{HashMap, HashSet},
1699 U256,
1700 };
1701 use arbitrary::Arbitrary;
1702 use rand::{rngs::StdRng, Rng, SeedableRng};
1703 use reth_primitives_traits::Account;
1704 use reth_trie::{updates::StorageTrieUpdates, HashBuilder, MultiProof, EMPTY_ROOT_HASH};
1705 use reth_trie_common::{
1706 proof::{ProofNodes, ProofRetainer},
1707 BranchNode, BranchNodeMasks, BranchNodeMasksMap, LeafNode, StorageMultiProof, TrieMask,
1708 };
1709
1710 #[test]
1711 fn reveal_account_path_twice() {
1712 let provider_factory = DefaultTrieNodeProviderFactory;
1713 let mut sparse = SparseStateTrie::<ParallelSparseTrie>::default();
1714
1715 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1716 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1717 Nibbles::default(),
1718 leaf_value.clone(),
1719 )));
1720 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1721 Nibbles::default(),
1722 leaf_value.clone(),
1723 )));
1724
1725 let multiproof = MultiProof {
1726 account_subtree: ProofNodes::from_iter([
1727 (
1728 Nibbles::default(),
1729 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1730 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1731 state_mask: TrieMask::new(0b11),
1732 }))
1733 .into(),
1734 ),
1735 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1736 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1737 ]),
1738 ..Default::default()
1739 };
1740
1741 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1743 assert!(matches!(
1744 sparse.state_trie_ref().unwrap().find_leaf(&Nibbles::from_nibbles([0x0]), None),
1745 Ok(LeafLookup::Exists)
1746 ));
1747 assert_eq!(
1748 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
1749 Some(&leaf_value)
1750 );
1751
1752 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &provider_factory).unwrap();
1755 assert!(matches!(
1756 sparse.state_trie_ref().unwrap().find_leaf(&Nibbles::from_nibbles([0x0]), None),
1757 Ok(LeafLookup::NonExistent)
1758 ));
1759 assert!(sparse
1760 .state_trie_ref()
1761 .unwrap()
1762 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1763 .is_none());
1764
1765 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1768 assert!(matches!(
1769 sparse.state_trie_ref().unwrap().find_leaf(&Nibbles::from_nibbles([0x0]), None),
1770 Ok(LeafLookup::NonExistent)
1771 ));
1772 assert!(sparse
1773 .state_trie_ref()
1774 .unwrap()
1775 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1776 .is_none());
1777 }
1778
1779 #[test]
1780 fn reveal_storage_path_twice() {
1781 let provider_factory = DefaultTrieNodeProviderFactory;
1782 let mut sparse = SparseStateTrie::<ParallelSparseTrie>::default();
1783
1784 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1785 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1786 Nibbles::default(),
1787 leaf_value.clone(),
1788 )));
1789 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1790 Nibbles::default(),
1791 leaf_value.clone(),
1792 )));
1793
1794 let multiproof = MultiProof {
1795 storages: HashMap::from_iter([(
1796 B256::ZERO,
1797 StorageMultiProof {
1798 root: B256::ZERO,
1799 subtree: ProofNodes::from_iter([
1800 (
1801 Nibbles::default(),
1802 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1803 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1804 state_mask: TrieMask::new(0b11),
1805 }))
1806 .into(),
1807 ),
1808 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1809 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1810 ]),
1811 branch_node_masks: Default::default(),
1812 },
1813 )]),
1814 ..Default::default()
1815 };
1816
1817 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1819 assert!(matches!(
1820 sparse
1821 .storage_trie_ref(&B256::ZERO)
1822 .unwrap()
1823 .find_leaf(&Nibbles::from_nibbles([0x0]), None),
1824 Ok(LeafLookup::Exists)
1825 ));
1826 assert_eq!(
1827 sparse
1828 .storage_trie_ref(&B256::ZERO)
1829 .unwrap()
1830 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
1831 Some(&leaf_value)
1832 );
1833
1834 sparse
1837 .remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0]), &provider_factory)
1838 .unwrap();
1839 assert!(matches!(
1840 sparse
1841 .storage_trie_ref(&B256::ZERO)
1842 .unwrap()
1843 .find_leaf(&Nibbles::from_nibbles([0x0]), None),
1844 Ok(LeafLookup::NonExistent)
1845 ));
1846 assert!(sparse
1847 .storage_trie_ref(&B256::ZERO)
1848 .unwrap()
1849 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1850 .is_none());
1851
1852 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1855 assert!(matches!(
1856 sparse
1857 .storage_trie_ref(&B256::ZERO)
1858 .unwrap()
1859 .find_leaf(&Nibbles::from_nibbles([0x0]), None),
1860 Ok(LeafLookup::NonExistent)
1861 ));
1862 assert!(sparse
1863 .storage_trie_ref(&B256::ZERO)
1864 .unwrap()
1865 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1866 .is_none());
1867 }
1868
1869 #[test]
1870 fn reveal_v2_proof_nodes() {
1871 let provider_factory = DefaultTrieNodeProviderFactory;
1872 let mut sparse = SparseStateTrie::<ParallelSparseTrie>::default();
1873
1874 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1875 let leaf_1_node = TrieNode::Leaf(LeafNode::new(Nibbles::default(), leaf_value.clone()));
1876 let leaf_2_node = TrieNode::Leaf(LeafNode::new(Nibbles::default(), leaf_value.clone()));
1877
1878 let branch_node = TrieNode::Branch(BranchNode {
1879 stack: vec![
1880 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1_node)),
1881 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2_node)),
1882 ],
1883 state_mask: TrieMask::new(0b11),
1884 });
1885
1886 let v2_proof_nodes = vec![
1888 ProofTrieNode {
1889 path: Nibbles::default(),
1890 node: branch_node,
1891 masks: Some(BranchNodeMasks {
1892 hash_mask: TrieMask::default(),
1893 tree_mask: TrieMask::default(),
1894 }),
1895 },
1896 ProofTrieNode { path: Nibbles::from_nibbles([0x0]), node: leaf_1_node, masks: None },
1897 ProofTrieNode { path: Nibbles::from_nibbles([0x1]), node: leaf_2_node, masks: None },
1898 ];
1899
1900 sparse.reveal_account_v2_proof_nodes(v2_proof_nodes.clone()).unwrap();
1902
1903 assert!(matches!(
1905 sparse.state_trie_ref().unwrap().find_leaf(&Nibbles::from_nibbles([0x0]), None),
1906 Ok(LeafLookup::Exists)
1907 ));
1908 assert_eq!(
1909 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
1910 Some(&leaf_value)
1911 );
1912
1913 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &provider_factory).unwrap();
1915 assert!(sparse
1916 .state_trie_ref()
1917 .unwrap()
1918 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1919 .is_none());
1920
1921 sparse.reveal_account_v2_proof_nodes(v2_proof_nodes).unwrap();
1923 assert!(sparse
1924 .state_trie_ref()
1925 .unwrap()
1926 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1927 .is_none());
1928 }
1929
1930 #[test]
1931 fn reveal_storage_v2_proof_nodes() {
1932 let provider_factory = DefaultTrieNodeProviderFactory;
1933 let mut sparse = SparseStateTrie::<ParallelSparseTrie>::default();
1934
1935 let storage_value: Vec<u8> = alloy_rlp::encode_fixed_size(&U256::from(42)).to_vec();
1936 let leaf_1_node = TrieNode::Leaf(LeafNode::new(Nibbles::default(), storage_value.clone()));
1937 let leaf_2_node = TrieNode::Leaf(LeafNode::new(Nibbles::default(), storage_value.clone()));
1938
1939 let branch_node = TrieNode::Branch(BranchNode {
1940 stack: vec![
1941 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_1_node)),
1942 RlpNode::from_rlp(&alloy_rlp::encode(&leaf_2_node)),
1943 ],
1944 state_mask: TrieMask::new(0b11),
1945 });
1946
1947 let v2_proof_nodes = vec![
1948 ProofTrieNode { path: Nibbles::default(), node: branch_node, masks: None },
1949 ProofTrieNode { path: Nibbles::from_nibbles([0x0]), node: leaf_1_node, masks: None },
1950 ProofTrieNode { path: Nibbles::from_nibbles([0x1]), node: leaf_2_node, masks: None },
1951 ];
1952
1953 sparse.reveal_storage_v2_proof_nodes(B256::ZERO, v2_proof_nodes.clone()).unwrap();
1955
1956 assert!(matches!(
1958 sparse
1959 .storage_trie_ref(&B256::ZERO)
1960 .unwrap()
1961 .find_leaf(&Nibbles::from_nibbles([0x0]), None),
1962 Ok(LeafLookup::Exists)
1963 ));
1964 assert_eq!(
1965 sparse
1966 .storage_trie_ref(&B256::ZERO)
1967 .unwrap()
1968 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
1969 Some(&storage_value)
1970 );
1971
1972 sparse
1974 .remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0]), &provider_factory)
1975 .unwrap();
1976 assert!(sparse
1977 .storage_trie_ref(&B256::ZERO)
1978 .unwrap()
1979 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1980 .is_none());
1981
1982 sparse.reveal_storage_v2_proof_nodes(B256::ZERO, v2_proof_nodes).unwrap();
1984 assert!(sparse
1985 .storage_trie_ref(&B256::ZERO)
1986 .unwrap()
1987 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1988 .is_none());
1989 }
1990
1991 #[test]
1992 fn take_trie_updates() {
1993 reth_tracing::init_test_tracing();
1994
1995 let mut rng = StdRng::seed_from_u64(1);
1997
1998 let mut bytes = [0u8; 1024];
1999 rng.fill(bytes.as_mut_slice());
2000
2001 let slot_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
2002 let slot_path_1 = Nibbles::unpack(slot_1);
2003 let value_1 = U256::from(rng.random::<u64>());
2004 let slot_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
2005 let slot_path_2 = Nibbles::unpack(slot_2);
2006 let value_2 = U256::from(rng.random::<u64>());
2007 let slot_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
2008 let slot_path_3 = Nibbles::unpack(slot_3);
2009 let value_3 = U256::from(rng.random::<u64>());
2010
2011 let mut storage_hash_builder = HashBuilder::default()
2012 .with_proof_retainer(ProofRetainer::from_iter([slot_path_1, slot_path_2]));
2013 storage_hash_builder.add_leaf(slot_path_1, &alloy_rlp::encode_fixed_size(&value_1));
2014 storage_hash_builder.add_leaf(slot_path_2, &alloy_rlp::encode_fixed_size(&value_2));
2015
2016 let storage_root = storage_hash_builder.root();
2017 let storage_proof_nodes = storage_hash_builder.take_proof_nodes();
2018 let storage_branch_node_masks = BranchNodeMasksMap::from_iter([
2019 (
2020 Nibbles::default(),
2021 BranchNodeMasks { hash_mask: TrieMask::new(0b010), tree_mask: TrieMask::default() },
2022 ),
2023 (
2024 Nibbles::from_nibbles([0x1]),
2025 BranchNodeMasks { hash_mask: TrieMask::new(0b11), tree_mask: TrieMask::default() },
2026 ),
2027 ]);
2028
2029 let address_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
2030 let address_path_1 = Nibbles::unpack(address_1);
2031 let account_1 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
2032 let mut trie_account_1 = account_1.into_trie_account(storage_root);
2033 let address_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
2034 let address_path_2 = Nibbles::unpack(address_2);
2035 let account_2 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
2036 let mut trie_account_2 = account_2.into_trie_account(EMPTY_ROOT_HASH);
2037
2038 let mut hash_builder = HashBuilder::default()
2039 .with_proof_retainer(ProofRetainer::from_iter([address_path_1, address_path_2]));
2040 hash_builder.add_leaf(address_path_1, &alloy_rlp::encode(trie_account_1));
2041 hash_builder.add_leaf(address_path_2, &alloy_rlp::encode(trie_account_2));
2042
2043 let root = hash_builder.root();
2044 let proof_nodes = hash_builder.take_proof_nodes();
2045
2046 let provider_factory = DefaultTrieNodeProviderFactory;
2047 let mut sparse = SparseStateTrie::<ParallelSparseTrie>::default().with_updates(true);
2048 sparse
2049 .reveal_decoded_multiproof(
2050 MultiProof {
2051 account_subtree: proof_nodes,
2052 branch_node_masks: BranchNodeMasksMap::from_iter([(
2053 Nibbles::from_nibbles([0x1]),
2054 BranchNodeMasks {
2055 hash_mask: TrieMask::new(0b00),
2056 tree_mask: TrieMask::default(),
2057 },
2058 )]),
2059 storages: HashMap::from_iter([
2060 (
2061 address_1,
2062 StorageMultiProof {
2063 root,
2064 subtree: storage_proof_nodes.clone(),
2065 branch_node_masks: storage_branch_node_masks.clone(),
2066 },
2067 ),
2068 (
2069 address_2,
2070 StorageMultiProof {
2071 root,
2072 subtree: storage_proof_nodes,
2073 branch_node_masks: storage_branch_node_masks,
2074 },
2075 ),
2076 ]),
2077 }
2078 .try_into()
2079 .unwrap(),
2080 )
2081 .unwrap();
2082
2083 assert_eq!(sparse.root(&provider_factory).unwrap(), root);
2084
2085 let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
2086 let address_path_3 = Nibbles::unpack(address_3);
2087 let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
2088 let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
2089
2090 sparse
2091 .update_account_leaf(
2092 address_path_3,
2093 alloy_rlp::encode(trie_account_3),
2094 &provider_factory,
2095 )
2096 .unwrap();
2097
2098 sparse
2099 .update_storage_leaf(
2100 address_1,
2101 slot_path_3,
2102 alloy_rlp::encode(value_3),
2103 &provider_factory,
2104 )
2105 .unwrap();
2106 trie_account_1.storage_root = sparse.storage_root(&address_1).unwrap();
2107 sparse
2108 .update_account_leaf(
2109 address_path_1,
2110 alloy_rlp::encode(trie_account_1),
2111 &provider_factory,
2112 )
2113 .unwrap();
2114
2115 sparse.wipe_storage(address_2).unwrap();
2116 trie_account_2.storage_root = sparse.storage_root(&address_2).unwrap();
2117 sparse
2118 .update_account_leaf(
2119 address_path_2,
2120 alloy_rlp::encode(trie_account_2),
2121 &provider_factory,
2122 )
2123 .unwrap();
2124
2125 sparse.root(&provider_factory).unwrap();
2126
2127 let sparse_updates = sparse.take_trie_updates().unwrap();
2128 pretty_assertions::assert_eq!(
2130 sparse_updates,
2131 TrieUpdates {
2132 account_nodes: HashMap::default(),
2133 storage_tries: HashMap::from_iter([(
2134 b256!("0x1100000000000000000000000000000000000000000000000000000000000000"),
2135 StorageTrieUpdates {
2136 is_deleted: true,
2137 storage_nodes: HashMap::default(),
2138 removed_nodes: HashSet::default()
2139 }
2140 )]),
2141 removed_nodes: HashSet::default()
2142 }
2143 );
2144 }
2145
2146 #[test]
2147 fn test_filter_map_revealed_nodes() {
2148 let mut revealed_nodes = HashSet::from_iter([Nibbles::from_nibbles([0x0])]);
2149 let leaf = TrieNode::Leaf(LeafNode::new(Nibbles::default(), alloy_rlp::encode([])));
2150 let leaf_encoded = alloy_rlp::encode(&leaf);
2151 let branch = TrieNode::Branch(BranchNode::new(
2152 vec![RlpNode::from_rlp(&leaf_encoded), RlpNode::from_rlp(&leaf_encoded)],
2153 TrieMask::new(0b11),
2154 ));
2155 let proof_nodes = alloy_trie::proof::DecodedProofNodes::from_iter([
2156 (Nibbles::default(), branch.clone()),
2157 (Nibbles::from_nibbles([0x0]), leaf.clone()),
2158 (Nibbles::from_nibbles([0x1]), leaf.clone()),
2159 ]);
2160
2161 let branch_node_masks = BranchNodeMasksMap::default();
2162
2163 let decoded =
2164 filter_map_revealed_nodes(proof_nodes, &mut revealed_nodes, &branch_node_masks)
2165 .unwrap();
2166
2167 assert_eq!(
2168 decoded,
2169 FilterMappedProofNodes {
2170 root_node: Some(ProofTrieNode {
2171 path: Nibbles::default(),
2172 node: branch,
2173 masks: None,
2174 }),
2175 nodes: vec![ProofTrieNode {
2176 path: Nibbles::from_nibbles([0x1]),
2177 node: leaf,
2178 masks: None,
2179 }],
2180 new_nodes: 4,
2182 metric_values: ProofNodesMetricValues {
2184 total_nodes: 3,
2186 skipped_nodes: 1,
2188 },
2189 }
2190 );
2191 }
2192}