1use crate::{
2 provider::{TrieNodeProvider, TrieNodeProviderFactory},
3 traits::SparseTrieInterface,
4 RevealedSparseNode, SerialSparseTrie, SparseTrie, TrieMasks,
5};
6use alloc::{collections::VecDeque, vec::Vec};
7use alloy_primitives::{
8 map::{B256Map, HashMap, 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 DecodedMultiProof, DecodedStorageMultiProof, MultiProof, Nibbles, RlpNode, StorageMultiProof,
19 TrieAccount, TrieMask, TrieNode, EMPTY_ROOT_HASH, TRIE_ACCOUNT_RLP_MAX_SIZE,
20};
21use tracing::trace;
22
23#[derive(Debug)]
26pub struct ClearedSparseStateTrie<
27 A = SerialSparseTrie, S = SerialSparseTrie, >(SparseStateTrie<A, S>);
30
31impl<A, S> ClearedSparseStateTrie<A, S>
32where
33 A: SparseTrieInterface,
34 S: SparseTrieInterface,
35{
36 pub fn from_state_trie(mut trie: SparseStateTrie<A, S>) -> Self {
39 trie.state = trie.state.clear();
40 trie.revealed_account_paths.clear();
41 trie.storage.clear();
42 trie.account_rlp_buf.clear();
43 Self(trie)
44 }
45
46 pub fn into_inner(self) -> SparseStateTrie<A, S> {
48 self.0
49 }
50}
51
52#[derive(Debug)]
53pub struct SparseStateTrie<
55 A = SerialSparseTrie, S = SerialSparseTrie, > {
58 state: SparseTrie<A>,
60 revealed_account_paths: HashSet<Nibbles>,
62 storage: StorageTries<S>,
64 retain_updates: bool,
66 account_rlp_buf: Vec<u8>,
68 #[cfg(feature = "metrics")]
70 metrics: crate::metrics::SparseStateTrieMetrics,
71}
72
73impl<A, S> Default for SparseStateTrie<A, S>
74where
75 A: Default,
76 S: Default,
77{
78 fn default() -> Self {
79 Self {
80 state: Default::default(),
81 revealed_account_paths: Default::default(),
82 storage: Default::default(),
83 retain_updates: false,
84 account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
85 #[cfg(feature = "metrics")]
86 metrics: Default::default(),
87 }
88 }
89}
90
91#[cfg(test)]
92impl SparseStateTrie {
93 pub fn from_state(state: SparseTrie) -> Self {
95 Self { state, ..Default::default() }
96 }
97}
98
99impl<A, S> SparseStateTrie<A, S> {
100 pub const fn with_updates(mut self, retain_updates: bool) -> Self {
102 self.retain_updates = retain_updates;
103 self
104 }
105
106 pub fn with_accounts_trie(mut self, trie: SparseTrie<A>) -> Self {
108 self.state = trie;
109 self
110 }
111
112 pub fn with_default_storage_trie(mut self, trie: SparseTrie<S>) -> Self {
114 self.storage.default_trie = trie;
115 self
116 }
117}
118
119impl<A, S> SparseStateTrie<A, S>
120where
121 A: SparseTrieInterface + Default,
122 S: SparseTrieInterface + Default + Clone,
123{
124 pub fn new() -> Self {
126 Self::default()
127 }
128
129 pub fn is_account_revealed(&self, account: B256) -> bool {
131 self.revealed_account_paths.contains(&Nibbles::unpack(account))
132 }
133
134 pub fn check_valid_account_witness(&self, address: B256) -> bool {
136 let path = Nibbles::unpack(address);
137 let trie = match self.state_trie_ref() {
138 Some(t) => t,
139 None => return false,
140 };
141
142 trie.find_leaf(&path, None).is_ok()
143 }
144
145 pub fn check_valid_storage_witness(&self, address: B256, slot: B256) -> bool {
147 let path = Nibbles::unpack(slot);
148 let trie = match self.storage_trie_ref(&address) {
149 Some(t) => t,
150 None => return false,
151 };
152
153 trie.find_leaf(&path, None).is_ok()
154 }
155
156 pub fn is_storage_slot_revealed(&self, account: B256, slot: B256) -> bool {
158 self.storage
159 .revealed_paths
160 .get(&account)
161 .is_some_and(|slots| slots.contains(&Nibbles::unpack(slot)))
162 }
163
164 pub fn get_account_value(&self, account: &B256) -> Option<&Vec<u8>> {
166 self.state.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(account))
167 }
168
169 pub fn get_storage_slot_value(&self, account: &B256, slot: &B256) -> Option<&Vec<u8>> {
171 self.storage.tries.get(account)?.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(slot))
172 }
173
174 pub const fn state_trie_ref(&self) -> Option<&A> {
176 self.state.as_revealed_ref()
177 }
178
179 pub fn storage_trie_ref(&self, address: &B256) -> Option<&S> {
181 self.storage.tries.get(address).and_then(|e| e.as_revealed_ref())
182 }
183
184 pub fn storage_trie_mut(&mut self, address: &B256) -> Option<&mut S> {
186 self.storage.tries.get_mut(address).and_then(|e| e.as_revealed_mut())
187 }
188
189 pub fn take_storage_trie(&mut self, address: &B256) -> Option<SparseTrie<S>> {
191 self.storage.tries.remove(address)
192 }
193
194 pub fn insert_storage_trie(&mut self, address: B256, storage_trie: SparseTrie<S>) {
196 self.storage.tries.insert(address, storage_trie);
197 }
198
199 pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
202 let decoded_multiproof = multiproof.try_into()?;
204
205 self.reveal_decoded_multiproof(decoded_multiproof)
207 }
208
209 pub fn reveal_decoded_multiproof(
212 &mut self,
213 multiproof: DecodedMultiProof,
214 ) -> SparseStateTrieResult<()> {
215 let DecodedMultiProof {
216 account_subtree,
217 storages,
218 branch_node_hash_masks,
219 branch_node_tree_masks,
220 } = multiproof;
221
222 self.reveal_decoded_account_multiproof(
224 account_subtree,
225 branch_node_hash_masks,
226 branch_node_tree_masks,
227 )?;
228
229 #[cfg(not(feature = "std"))]
230 {
232 for (account, storage_subtree) in storages {
233 self.reveal_decoded_storage_multiproof(account, storage_subtree)?;
234 }
235
236 Ok(())
237 }
238
239 #[cfg(feature = "std")]
240 {
242 use rayon::iter::{ParallelBridge, ParallelIterator};
243
244 let (tx, rx) = std::sync::mpsc::channel();
245 let retain_updates = self.retain_updates;
246
247 storages
251 .into_iter()
252 .map(|(account, storage_subtree)| {
253 let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
254 let trie = self.storage.take_or_create_trie(&account);
255 (account, storage_subtree, revealed_nodes, trie)
256 })
257 .par_bridge()
258 .map(|(account, storage_subtree, mut revealed_nodes, mut trie)| {
259 let result = Self::reveal_decoded_storage_multiproof_inner(
260 account,
261 storage_subtree,
262 &mut revealed_nodes,
263 &mut trie,
264 retain_updates,
265 );
266
267 (account, revealed_nodes, trie, result)
268 })
269 .for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
270
271 drop(tx);
272
273 let mut any_err = Ok(());
276 for (account, revealed_nodes, trie, result) in rx {
277 self.storage.revealed_paths.insert(account, revealed_nodes);
278 self.storage.tries.insert(account, trie);
279 if let Ok(_metric_values) = result {
280 #[cfg(feature = "metrics")]
281 {
282 self.metrics
283 .increment_total_storage_nodes(_metric_values.total_nodes as u64);
284 self.metrics
285 .increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
286 }
287 } else {
288 any_err = result.map(|_| ());
289 }
290 }
291
292 any_err
293 }
294 }
295
296 pub fn reveal_account_multiproof(
298 &mut self,
299 account_subtree: ProofNodes,
300 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
301 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
302 ) -> SparseStateTrieResult<()> {
303 let decoded_multiproof = account_subtree.try_into()?;
305 self.reveal_decoded_account_multiproof(
306 decoded_multiproof,
307 branch_node_hash_masks,
308 branch_node_tree_masks,
309 )
310 }
311
312 pub fn reveal_decoded_account_multiproof(
314 &mut self,
315 account_subtree: DecodedProofNodes,
316 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
317 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
318 ) -> SparseStateTrieResult<()> {
319 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values: _metric_values } =
320 filter_map_revealed_nodes(
321 account_subtree,
322 &mut self.revealed_account_paths,
323 &branch_node_hash_masks,
324 &branch_node_tree_masks,
325 )?;
326 #[cfg(feature = "metrics")]
327 {
328 self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
329 self.metrics.increment_skipped_account_nodes(_metric_values.skipped_nodes as u64);
330 }
331
332 if let Some(root_node) = root_node {
333 trace!(target: "trie::sparse", ?root_node, "Revealing root account node");
335 let trie =
336 self.state.reveal_root(root_node.node, root_node.masks, self.retain_updates)?;
337
338 trie.reserve_nodes(new_nodes);
341
342 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes");
343 trie.reveal_nodes(nodes)?;
344 }
345
346 Ok(())
347 }
348
349 pub fn reveal_storage_multiproof(
351 &mut self,
352 account: B256,
353 storage_subtree: StorageMultiProof,
354 ) -> SparseStateTrieResult<()> {
355 let decoded_multiproof = storage_subtree.try_into()?;
357 self.reveal_decoded_storage_multiproof(account, decoded_multiproof)
358 }
359
360 pub fn reveal_decoded_storage_multiproof(
362 &mut self,
363 account: B256,
364 storage_subtree: DecodedStorageMultiProof,
365 ) -> SparseStateTrieResult<()> {
366 let (trie, revealed_paths) = self.storage.get_trie_and_revealed_paths_mut(account);
367 let _metric_values = Self::reveal_decoded_storage_multiproof_inner(
368 account,
369 storage_subtree,
370 revealed_paths,
371 trie,
372 self.retain_updates,
373 )?;
374
375 #[cfg(feature = "metrics")]
376 {
377 self.metrics.increment_total_storage_nodes(_metric_values.total_nodes as u64);
378 self.metrics.increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
379 }
380
381 Ok(())
382 }
383
384 fn reveal_decoded_storage_multiproof_inner(
387 account: B256,
388 storage_subtree: DecodedStorageMultiProof,
389 revealed_nodes: &mut HashSet<Nibbles>,
390 trie: &mut SparseTrie<S>,
391 retain_updates: bool,
392 ) -> SparseStateTrieResult<ProofNodesMetricValues> {
393 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values } =
394 filter_map_revealed_nodes(
395 storage_subtree.subtree,
396 revealed_nodes,
397 &storage_subtree.branch_node_hash_masks,
398 &storage_subtree.branch_node_tree_masks,
399 )?;
400
401 if let Some(root_node) = root_node {
402 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node");
404 let trie = trie.reveal_root(root_node.node, root_node.masks, retain_updates)?;
405
406 trie.reserve_nodes(new_nodes);
409
410 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes");
411 trie.reveal_nodes(nodes)?;
412 }
413
414 Ok(metric_values)
415 }
416
417 pub fn reveal_witness(
421 &mut self,
422 state_root: B256,
423 witness: &B256Map<Bytes>,
424 ) -> SparseStateTrieResult<()> {
425 let mut queue = VecDeque::from([(state_root, Nibbles::default(), None)]);
428
429 while let Some((hash, path, maybe_account)) = queue.pop_front() {
430 let Some(trie_node_bytes) = witness.get(&hash) else { continue };
432 let trie_node = TrieNode::decode(&mut &trie_node_bytes[..])?;
433
434 match &trie_node {
436 TrieNode::Branch(branch) => {
437 for (idx, maybe_child) in branch.as_ref().children() {
438 if let Some(child_hash) = maybe_child.and_then(RlpNode::as_hash) {
439 let mut child_path = path;
440 child_path.push_unchecked(idx);
441 queue.push_back((child_hash, child_path, maybe_account));
442 }
443 }
444 }
445 TrieNode::Extension(ext) => {
446 if let Some(child_hash) = ext.child.as_hash() {
447 let mut child_path = path;
448 child_path.extend(&ext.key);
449 queue.push_back((child_hash, child_path, maybe_account));
450 }
451 }
452 TrieNode::Leaf(leaf) => {
453 let mut full_path = path;
454 full_path.extend(&leaf.key);
455 if maybe_account.is_none() {
456 let hashed_address = B256::from_slice(&full_path.pack());
457 let account = TrieAccount::decode(&mut &leaf.value[..])?;
458 if account.storage_root != EMPTY_ROOT_HASH {
459 queue.push_back((
460 account.storage_root,
461 Nibbles::default(),
462 Some(hashed_address),
463 ));
464 }
465 }
466 }
467 TrieNode::EmptyRoot => {} };
469
470 if let Some(account) = maybe_account {
472 if self
474 .storage
475 .revealed_paths
476 .get(&account)
477 .is_none_or(|paths| !paths.contains(&path))
478 {
479 let retain_updates = self.retain_updates;
480 let (storage_trie_entry, revealed_storage_paths) =
481 self.storage.get_trie_and_revealed_paths_mut(account);
482
483 if path.is_empty() {
484 storage_trie_entry.reveal_root(
486 trie_node,
487 TrieMasks::none(),
488 retain_updates,
489 )?;
490 } else {
491 storage_trie_entry
493 .as_revealed_mut()
494 .ok_or(SparseTrieErrorKind::Blind)?
495 .reveal_node(path, trie_node, TrieMasks::none())?;
496 }
497
498 revealed_storage_paths.insert(path);
500 }
501 }
502 else if !self.revealed_account_paths.contains(&path) {
504 if path.is_empty() {
505 self.state.reveal_root(trie_node, TrieMasks::none(), self.retain_updates)?;
507 } else {
508 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?.reveal_node(
510 path,
511 trie_node,
512 TrieMasks::none(),
513 )?;
514 }
515
516 self.revealed_account_paths.insert(path);
518 }
519 }
520
521 Ok(())
522 }
523
524 pub fn wipe_storage(&mut self, address: B256) -> SparseStateTrieResult<()> {
526 if let Some(trie) = self.storage.tries.get_mut(&address) {
527 trie.wipe()?;
528 }
529 Ok(())
530 }
531
532 pub fn calculate_subtries(&mut self) {
536 if let SparseTrie::Revealed(trie) = &mut self.state {
537 trie.update_subtrie_hashes();
538 }
539 }
540
541 pub fn storage_root(&mut self, account: B256) -> Option<B256> {
543 self.storage.tries.get_mut(&account).and_then(|trie| trie.root())
544 }
545
546 fn revealed_trie_mut(
550 &mut self,
551 provider_factory: impl TrieNodeProviderFactory,
552 ) -> SparseStateTrieResult<&mut A> {
553 match self.state {
554 SparseTrie::Blind(_) => {
555 let (root_node, hash_mask, tree_mask) = provider_factory
556 .account_node_provider()
557 .trie_node(&Nibbles::default())?
558 .map(|node| {
559 TrieNode::decode(&mut &node.node[..])
560 .map(|decoded| (decoded, node.hash_mask, node.tree_mask))
561 })
562 .transpose()?
563 .unwrap_or((TrieNode::EmptyRoot, None, None));
564 self.state
565 .reveal_root(root_node, TrieMasks { hash_mask, tree_mask }, self.retain_updates)
566 .map_err(Into::into)
567 }
568 SparseTrie::Revealed(ref mut trie) => Ok(trie),
569 }
570 }
571
572 pub fn root(
576 &mut self,
577 provider_factory: impl TrieNodeProviderFactory,
578 ) -> SparseStateTrieResult<B256> {
579 #[cfg(feature = "metrics")]
581 self.metrics.record();
582
583 Ok(self.revealed_trie_mut(provider_factory)?.root())
584 }
585
586 pub fn root_with_updates(
588 &mut self,
589 provider_factory: impl TrieNodeProviderFactory,
590 ) -> SparseStateTrieResult<(B256, TrieUpdates)> {
591 #[cfg(feature = "metrics")]
593 self.metrics.record();
594
595 let storage_tries = self.storage_trie_updates();
596 let revealed = self.revealed_trie_mut(provider_factory)?;
597
598 let (root, updates) = (revealed.root(), revealed.take_updates());
599 let updates = TrieUpdates {
600 account_nodes: updates.updated_nodes,
601 removed_nodes: updates.removed_nodes,
602 storage_tries,
603 };
604 Ok((root, updates))
605 }
606
607 pub fn storage_trie_updates(&mut self) -> B256Map<StorageTrieUpdates> {
611 self.storage
612 .tries
613 .iter_mut()
614 .map(|(address, trie)| {
615 let trie = trie.as_revealed_mut().unwrap();
616 let updates = trie.take_updates();
617 let updates = StorageTrieUpdates {
618 is_deleted: updates.wiped,
619 storage_nodes: updates.updated_nodes,
620 removed_nodes: updates.removed_nodes,
621 };
622 (*address, updates)
623 })
624 .filter(|(_, updates)| !updates.is_empty())
625 .collect()
626 }
627
628 pub fn take_trie_updates(&mut self) -> Option<TrieUpdates> {
632 let storage_tries = self.storage_trie_updates();
633 self.state.as_revealed_mut().map(|state| {
634 let updates = state.take_updates();
635 TrieUpdates {
636 account_nodes: updates.updated_nodes,
637 removed_nodes: updates.removed_nodes,
638 storage_tries,
639 }
640 })
641 }
642
643 pub fn update_account_leaf(
645 &mut self,
646 path: Nibbles,
647 value: Vec<u8>,
648 provider_factory: impl TrieNodeProviderFactory,
649 ) -> SparseStateTrieResult<()> {
650 if !self.revealed_account_paths.contains(&path) {
651 self.revealed_account_paths.insert(path);
652 }
653
654 let provider = provider_factory.account_node_provider();
655 self.state.update_leaf(path, value, provider)?;
656 Ok(())
657 }
658
659 pub fn update_storage_leaf(
661 &mut self,
662 address: B256,
663 slot: Nibbles,
664 value: Vec<u8>,
665 provider_factory: impl TrieNodeProviderFactory,
666 ) -> SparseStateTrieResult<()> {
667 let provider = provider_factory.storage_node_provider(address);
668 self.storage
669 .tries
670 .get_mut(&address)
671 .ok_or(SparseTrieErrorKind::Blind)?
672 .update_leaf(slot, value, provider)?;
673 self.storage.get_revealed_paths_mut(address).insert(slot);
674 Ok(())
675 }
676
677 pub fn update_account(
683 &mut self,
684 address: B256,
685 account: Account,
686 provider_factory: impl TrieNodeProviderFactory,
687 ) -> SparseStateTrieResult<bool> {
688 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
689 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
690 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
691 } else if self.is_account_revealed(address) {
692 trace!(target: "trie::sparse", ?address, "Retrieving storage root from account leaf to update account");
693 if let Some(value) = self.get_account_value(&address) {
695 TrieAccount::decode(&mut &value[..])?.storage_root
697 } else {
698 EMPTY_ROOT_HASH
700 }
701 } else {
702 return Err(SparseTrieErrorKind::Blind.into())
703 };
704
705 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
706 return Ok(false);
707 }
708
709 trace!(target: "trie::sparse", ?address, "Updating account");
710 let nibbles = Nibbles::unpack(address);
711 self.account_rlp_buf.clear();
712 account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
713 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
714
715 Ok(true)
716 }
717
718 pub fn update_account_storage_root(
725 &mut self,
726 address: B256,
727 provider_factory: impl TrieNodeProviderFactory,
728 ) -> SparseStateTrieResult<bool> {
729 if !self.is_account_revealed(address) {
730 return Err(SparseTrieErrorKind::Blind.into())
731 }
732
733 let Some(mut trie_account) = self
735 .get_account_value(&address)
736 .map(|v| TrieAccount::decode(&mut &v[..]))
737 .transpose()?
738 else {
739 trace!(target: "trie::sparse", ?address, "Account not found in trie, skipping storage root update");
740 return Ok(true)
741 };
742
743 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
746 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
747 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
748 } else {
749 EMPTY_ROOT_HASH
750 };
751
752 trie_account.storage_root = storage_root;
754
755 if trie_account == TrieAccount::default() {
757 return Ok(false)
758 }
759
760 trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
762 let nibbles = Nibbles::unpack(address);
763 self.account_rlp_buf.clear();
764 trie_account.encode(&mut self.account_rlp_buf);
765 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
766
767 Ok(true)
768 }
769
770 pub fn remove_account_leaf(
772 &mut self,
773 path: &Nibbles,
774 provider_factory: impl TrieNodeProviderFactory,
775 ) -> SparseStateTrieResult<()> {
776 let provider = provider_factory.account_node_provider();
777 self.state.remove_leaf(path, provider)?;
778 Ok(())
779 }
780
781 pub fn remove_storage_leaf(
783 &mut self,
784 address: B256,
785 slot: &Nibbles,
786 provider_factory: impl TrieNodeProviderFactory,
787 ) -> SparseStateTrieResult<()> {
788 let storage_trie =
789 self.storage.tries.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
790
791 let provider = provider_factory.storage_node_provider(address);
792 storage_trie.remove_leaf(slot, provider)?;
793 Ok(())
794 }
795}
796
797#[derive(Debug, Default)]
801struct StorageTries<S = SerialSparseTrie> {
802 tries: B256Map<SparseTrie<S>>,
804 cleared_tries: Vec<SparseTrie<S>>,
806 revealed_paths: B256Map<HashSet<Nibbles>>,
808 cleared_revealed_paths: Vec<HashSet<Nibbles>>,
810 default_trie: SparseTrie<S>,
812}
813
814impl<S: SparseTrieInterface> StorageTries<S> {
815 fn clear(&mut self) {
818 self.cleared_tries.extend(self.tries.drain().map(|(_, trie)| trie.clear()));
819 self.cleared_revealed_paths.extend(self.revealed_paths.drain().map(|(_, mut set)| {
820 set.clear();
821 set
822 }));
823 }
824}
825
826impl<S: SparseTrieInterface + Clone> StorageTries<S> {
827 fn get_revealed_paths_mut(&mut self, account: B256) -> &mut HashSet<Nibbles> {
830 self.revealed_paths
831 .entry(account)
832 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default())
833 }
834
835 fn get_trie_and_revealed_paths_mut(
838 &mut self,
839 account: B256,
840 ) -> (&mut SparseTrie<S>, &mut HashSet<Nibbles>) {
841 let trie = self.tries.entry(account).or_insert_with(|| {
842 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
843 });
844
845 let revealed_paths = self
846 .revealed_paths
847 .entry(account)
848 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default());
849
850 (trie, revealed_paths)
851 }
852
853 #[cfg(feature = "std")]
856 fn take_or_create_trie(&mut self, account: &B256) -> SparseTrie<S> {
857 self.tries.remove(account).unwrap_or_else(|| {
858 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
859 })
860 }
861
862 #[cfg(feature = "std")]
865 fn take_or_create_revealed_paths(&mut self, account: &B256) -> HashSet<Nibbles> {
866 self.revealed_paths
867 .remove(account)
868 .unwrap_or_else(|| self.cleared_revealed_paths.pop().unwrap_or_default())
869 }
870}
871
872#[derive(Debug, PartialEq, Eq, Default)]
873struct ProofNodesMetricValues {
874 total_nodes: usize,
876 skipped_nodes: usize,
878}
879
880#[derive(Debug, PartialEq, Eq)]
882struct FilterMappedProofNodes {
883 root_node: Option<RevealedSparseNode>,
885 nodes: Vec<RevealedSparseNode>,
887 new_nodes: usize,
890 metric_values: ProofNodesMetricValues,
892}
893
894fn filter_map_revealed_nodes(
898 proof_nodes: DecodedProofNodes,
899 revealed_nodes: &mut HashSet<Nibbles>,
900 branch_node_hash_masks: &HashMap<Nibbles, TrieMask>,
901 branch_node_tree_masks: &HashMap<Nibbles, TrieMask>,
902) -> SparseStateTrieResult<FilterMappedProofNodes> {
903 let mut result = FilterMappedProofNodes {
904 root_node: None,
905 nodes: Vec::with_capacity(proof_nodes.len()),
906 new_nodes: 0,
907 metric_values: Default::default(),
908 };
909
910 let proof_nodes_len = proof_nodes.len();
911 for (path, proof_node) in proof_nodes.into_inner() {
912 result.metric_values.total_nodes += 1;
913
914 let is_root = path.is_empty();
915
916 if !is_root && !revealed_nodes.insert(path) {
919 result.metric_values.skipped_nodes += 1;
920 continue
921 }
922
923 result.new_nodes += 1;
924
925 let masks = match &proof_node {
928 TrieNode::Branch(branch) => {
929 result.new_nodes += branch.state_mask.count_ones() as usize;
932 TrieMasks {
933 hash_mask: branch_node_hash_masks.get(&path).copied(),
934 tree_mask: branch_node_tree_masks.get(&path).copied(),
935 }
936 }
937 TrieNode::Extension(_) => {
938 result.new_nodes += 1;
940 TrieMasks::none()
941 }
942 _ => TrieMasks::none(),
943 };
944
945 let node = RevealedSparseNode { path, node: proof_node, masks };
946
947 if is_root {
948 if matches!(node.node, TrieNode::EmptyRoot) && proof_nodes_len > 1 {
950 return Err(SparseStateTrieErrorKind::InvalidRootNode {
951 path,
952 node: alloy_rlp::encode(&node.node).into(),
953 }
954 .into())
955 }
956
957 result.root_node = Some(node);
958
959 continue
960 }
961
962 result.nodes.push(node);
963 }
964
965 Ok(result)
966}
967
968#[cfg(test)]
969mod tests {
970 use super::*;
971 use crate::provider::DefaultTrieNodeProviderFactory;
972 use alloy_primitives::{
973 b256,
974 map::{HashMap, HashSet},
975 U256,
976 };
977 use arbitrary::Arbitrary;
978 use rand::{rngs::StdRng, Rng, SeedableRng};
979 use reth_primitives_traits::Account;
980 use reth_trie::{updates::StorageTrieUpdates, HashBuilder, MultiProof, EMPTY_ROOT_HASH};
981 use reth_trie_common::{
982 proof::{ProofNodes, ProofRetainer},
983 BranchNode, LeafNode, StorageMultiProof, TrieMask,
984 };
985
986 #[test]
987 fn reveal_account_path_twice() {
988 let provider_factory = DefaultTrieNodeProviderFactory;
989 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
990
991 let leaf_value = alloy_rlp::encode(TrieAccount::default());
992 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
993 Nibbles::default(),
994 leaf_value.clone(),
995 )));
996 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
997 Nibbles::default(),
998 leaf_value.clone(),
999 )));
1000
1001 let multiproof = MultiProof {
1002 account_subtree: ProofNodes::from_iter([
1003 (
1004 Nibbles::default(),
1005 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1006 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1007 state_mask: TrieMask::new(0b11),
1008 }))
1009 .into(),
1010 ),
1011 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1012 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1013 ]),
1014 ..Default::default()
1015 };
1016
1017 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1019 assert!(sparse
1020 .state_trie_ref()
1021 .unwrap()
1022 .nodes_ref()
1023 .contains_key(&Nibbles::from_nibbles([0x0])),);
1024 assert_eq!(
1025 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
1026 Some(&leaf_value)
1027 );
1028
1029 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &provider_factory).unwrap();
1032 assert!(!sparse
1033 .state_trie_ref()
1034 .unwrap()
1035 .nodes_ref()
1036 .contains_key(&Nibbles::from_nibbles([0x0])),);
1037 assert!(sparse
1038 .state_trie_ref()
1039 .unwrap()
1040 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1041 .is_none());
1042
1043 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1046 assert!(!sparse
1047 .state_trie_ref()
1048 .unwrap()
1049 .nodes_ref()
1050 .contains_key(&Nibbles::from_nibbles([0x0])));
1051 assert!(sparse
1052 .state_trie_ref()
1053 .unwrap()
1054 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1055 .is_none());
1056 }
1057
1058 #[test]
1059 fn reveal_storage_path_twice() {
1060 let provider_factory = DefaultTrieNodeProviderFactory;
1061 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
1062
1063 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1064 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1065 Nibbles::default(),
1066 leaf_value.clone(),
1067 )));
1068 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1069 Nibbles::default(),
1070 leaf_value.clone(),
1071 )));
1072
1073 let multiproof = MultiProof {
1074 storages: HashMap::from_iter([(
1075 B256::ZERO,
1076 StorageMultiProof {
1077 root: B256::ZERO,
1078 subtree: ProofNodes::from_iter([
1079 (
1080 Nibbles::default(),
1081 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1082 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1083 state_mask: TrieMask::new(0b11),
1084 }))
1085 .into(),
1086 ),
1087 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1088 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1089 ]),
1090 branch_node_hash_masks: Default::default(),
1091 branch_node_tree_masks: Default::default(),
1092 },
1093 )]),
1094 ..Default::default()
1095 };
1096
1097 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1099 assert!(sparse
1100 .storage_trie_ref(&B256::ZERO)
1101 .unwrap()
1102 .nodes_ref()
1103 .contains_key(&Nibbles::from_nibbles([0x0])),);
1104 assert_eq!(
1105 sparse
1106 .storage_trie_ref(&B256::ZERO)
1107 .unwrap()
1108 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
1109 Some(&leaf_value)
1110 );
1111
1112 sparse
1115 .remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0]), &provider_factory)
1116 .unwrap();
1117 assert!(!sparse
1118 .storage_trie_ref(&B256::ZERO)
1119 .unwrap()
1120 .nodes_ref()
1121 .contains_key(&Nibbles::from_nibbles([0x0])),);
1122 assert!(sparse
1123 .storage_trie_ref(&B256::ZERO)
1124 .unwrap()
1125 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1126 .is_none());
1127
1128 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1131 assert!(!sparse
1132 .storage_trie_ref(&B256::ZERO)
1133 .unwrap()
1134 .nodes_ref()
1135 .contains_key(&Nibbles::from_nibbles([0x0])));
1136 assert!(sparse
1137 .storage_trie_ref(&B256::ZERO)
1138 .unwrap()
1139 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1140 .is_none());
1141 }
1142
1143 #[test]
1144 fn take_trie_updates() {
1145 reth_tracing::init_test_tracing();
1146
1147 let mut rng = StdRng::seed_from_u64(1);
1149
1150 let mut bytes = [0u8; 1024];
1151 rng.fill(bytes.as_mut_slice());
1152
1153 let slot_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1154 let slot_path_1 = Nibbles::unpack(slot_1);
1155 let value_1 = U256::from(rng.random::<u64>());
1156 let slot_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1157 let slot_path_2 = Nibbles::unpack(slot_2);
1158 let value_2 = U256::from(rng.random::<u64>());
1159 let slot_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1160 let slot_path_3 = Nibbles::unpack(slot_3);
1161 let value_3 = U256::from(rng.random::<u64>());
1162
1163 let mut storage_hash_builder = HashBuilder::default()
1164 .with_proof_retainer(ProofRetainer::from_iter([slot_path_1, slot_path_2]));
1165 storage_hash_builder.add_leaf(slot_path_1, &alloy_rlp::encode_fixed_size(&value_1));
1166 storage_hash_builder.add_leaf(slot_path_2, &alloy_rlp::encode_fixed_size(&value_2));
1167
1168 let storage_root = storage_hash_builder.root();
1169 let storage_proof_nodes = storage_hash_builder.take_proof_nodes();
1170 let storage_branch_node_hash_masks = HashMap::from_iter([
1171 (Nibbles::default(), TrieMask::new(0b010)),
1172 (Nibbles::from_nibbles([0x1]), TrieMask::new(0b11)),
1173 ]);
1174
1175 let address_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1176 let address_path_1 = Nibbles::unpack(address_1);
1177 let account_1 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1178 let mut trie_account_1 = account_1.into_trie_account(storage_root);
1179 let address_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1180 let address_path_2 = Nibbles::unpack(address_2);
1181 let account_2 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1182 let mut trie_account_2 = account_2.into_trie_account(EMPTY_ROOT_HASH);
1183
1184 let mut hash_builder = HashBuilder::default()
1185 .with_proof_retainer(ProofRetainer::from_iter([address_path_1, address_path_2]));
1186 hash_builder.add_leaf(address_path_1, &alloy_rlp::encode(trie_account_1));
1187 hash_builder.add_leaf(address_path_2, &alloy_rlp::encode(trie_account_2));
1188
1189 let root = hash_builder.root();
1190 let proof_nodes = hash_builder.take_proof_nodes();
1191
1192 let provider_factory = DefaultTrieNodeProviderFactory;
1193 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default().with_updates(true);
1194 sparse
1195 .reveal_decoded_multiproof(
1196 MultiProof {
1197 account_subtree: proof_nodes,
1198 branch_node_hash_masks: HashMap::from_iter([(
1199 Nibbles::from_nibbles([0x1]),
1200 TrieMask::new(0b00),
1201 )]),
1202 branch_node_tree_masks: HashMap::default(),
1203 storages: HashMap::from_iter([
1204 (
1205 address_1,
1206 StorageMultiProof {
1207 root,
1208 subtree: storage_proof_nodes.clone(),
1209 branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
1210 branch_node_tree_masks: HashMap::default(),
1211 },
1212 ),
1213 (
1214 address_2,
1215 StorageMultiProof {
1216 root,
1217 subtree: storage_proof_nodes,
1218 branch_node_hash_masks: storage_branch_node_hash_masks,
1219 branch_node_tree_masks: HashMap::default(),
1220 },
1221 ),
1222 ]),
1223 }
1224 .try_into()
1225 .unwrap(),
1226 )
1227 .unwrap();
1228
1229 assert_eq!(sparse.root(&provider_factory).unwrap(), root);
1230
1231 let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1232 let address_path_3 = Nibbles::unpack(address_3);
1233 let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
1234 let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
1235
1236 sparse
1237 .update_account_leaf(
1238 address_path_3,
1239 alloy_rlp::encode(trie_account_3),
1240 &provider_factory,
1241 )
1242 .unwrap();
1243
1244 sparse
1245 .update_storage_leaf(
1246 address_1,
1247 slot_path_3,
1248 alloy_rlp::encode(value_3),
1249 &provider_factory,
1250 )
1251 .unwrap();
1252 trie_account_1.storage_root = sparse.storage_root(address_1).unwrap();
1253 sparse
1254 .update_account_leaf(
1255 address_path_1,
1256 alloy_rlp::encode(trie_account_1),
1257 &provider_factory,
1258 )
1259 .unwrap();
1260
1261 sparse.wipe_storage(address_2).unwrap();
1262 trie_account_2.storage_root = sparse.storage_root(address_2).unwrap();
1263 sparse
1264 .update_account_leaf(
1265 address_path_2,
1266 alloy_rlp::encode(trie_account_2),
1267 &provider_factory,
1268 )
1269 .unwrap();
1270
1271 sparse.root(&provider_factory).unwrap();
1272
1273 let sparse_updates = sparse.take_trie_updates().unwrap();
1274 pretty_assertions::assert_eq!(
1276 sparse_updates,
1277 TrieUpdates {
1278 account_nodes: HashMap::default(),
1279 storage_tries: HashMap::from_iter([(
1280 b256!("0x1100000000000000000000000000000000000000000000000000000000000000"),
1281 StorageTrieUpdates {
1282 is_deleted: true,
1283 storage_nodes: HashMap::default(),
1284 removed_nodes: HashSet::default()
1285 }
1286 )]),
1287 removed_nodes: HashSet::default()
1288 }
1289 );
1290 }
1291
1292 #[test]
1293 fn test_filter_map_revealed_nodes() {
1294 let mut revealed_nodes = HashSet::from_iter([Nibbles::from_nibbles([0x0])]);
1295 let leaf = TrieNode::Leaf(LeafNode::new(Nibbles::default(), alloy_rlp::encode([])));
1296 let leaf_encoded = alloy_rlp::encode(&leaf);
1297 let branch = TrieNode::Branch(BranchNode::new(
1298 vec![RlpNode::from_rlp(&leaf_encoded), RlpNode::from_rlp(&leaf_encoded)],
1299 TrieMask::new(0b11),
1300 ));
1301 let proof_nodes = alloy_trie::proof::DecodedProofNodes::from_iter([
1302 (Nibbles::default(), branch.clone()),
1303 (Nibbles::from_nibbles([0x0]), leaf.clone()),
1304 (Nibbles::from_nibbles([0x1]), leaf.clone()),
1305 ]);
1306
1307 let branch_node_hash_masks = HashMap::default();
1308 let branch_node_tree_masks = HashMap::default();
1309
1310 let decoded = filter_map_revealed_nodes(
1311 proof_nodes,
1312 &mut revealed_nodes,
1313 &branch_node_hash_masks,
1314 &branch_node_tree_masks,
1315 )
1316 .unwrap();
1317
1318 assert_eq!(
1319 decoded,
1320 FilterMappedProofNodes {
1321 root_node: Some(RevealedSparseNode {
1322 path: Nibbles::default(),
1323 node: branch,
1324 masks: TrieMasks::none(),
1325 }),
1326 nodes: vec![RevealedSparseNode {
1327 path: Nibbles::from_nibbles([0x1]),
1328 node: leaf,
1329 masks: TrieMasks::none(),
1330 }],
1331 new_nodes: 4,
1333 metric_values: ProofNodesMetricValues {
1335 total_nodes: 3,
1337 skipped_nodes: 1,
1339 },
1340 }
1341 );
1342 }
1343}