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 + Default,
34 S: SparseTrieInterface + Default,
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
113impl<A, S> SparseStateTrie<A, S>
114where
115 A: SparseTrieInterface + Default,
116 S: SparseTrieInterface + Default,
117{
118 pub fn new() -> Self {
120 Self::default()
121 }
122
123 pub fn is_account_revealed(&self, account: B256) -> bool {
125 self.revealed_account_paths.contains(&Nibbles::unpack(account))
126 }
127
128 pub fn check_valid_account_witness(&self, address: B256) -> bool {
130 let path = Nibbles::unpack(address);
131 let trie = match self.state_trie_ref() {
132 Some(t) => t,
133 None => return false,
134 };
135
136 trie.find_leaf(&path, None).is_ok()
137 }
138
139 pub fn check_valid_storage_witness(&self, address: B256, slot: B256) -> bool {
141 let path = Nibbles::unpack(slot);
142 let trie = match self.storage_trie_ref(&address) {
143 Some(t) => t,
144 None => return false,
145 };
146
147 trie.find_leaf(&path, None).is_ok()
148 }
149
150 pub fn is_storage_slot_revealed(&self, account: B256, slot: B256) -> bool {
152 self.storage
153 .revealed_paths
154 .get(&account)
155 .is_some_and(|slots| slots.contains(&Nibbles::unpack(slot)))
156 }
157
158 pub fn get_account_value(&self, account: &B256) -> Option<&Vec<u8>> {
160 self.state.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(account))
161 }
162
163 pub fn get_storage_slot_value(&self, account: &B256, slot: &B256) -> Option<&Vec<u8>> {
165 self.storage.tries.get(account)?.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(slot))
166 }
167
168 pub const fn state_trie_ref(&self) -> Option<&A> {
170 self.state.as_revealed_ref()
171 }
172
173 pub fn storage_trie_ref(&self, address: &B256) -> Option<&S> {
175 self.storage.tries.get(address).and_then(|e| e.as_revealed_ref())
176 }
177
178 pub fn storage_trie_mut(&mut self, address: &B256) -> Option<&mut S> {
180 self.storage.tries.get_mut(address).and_then(|e| e.as_revealed_mut())
181 }
182
183 pub fn take_storage_trie(&mut self, address: &B256) -> Option<SparseTrie<S>> {
185 self.storage.tries.remove(address)
186 }
187
188 pub fn insert_storage_trie(&mut self, address: B256, storage_trie: SparseTrie<S>) {
190 self.storage.tries.insert(address, storage_trie);
191 }
192
193 pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
196 let decoded_multiproof = multiproof.try_into()?;
198
199 self.reveal_decoded_multiproof(decoded_multiproof)
201 }
202
203 pub fn reveal_decoded_multiproof(
206 &mut self,
207 multiproof: DecodedMultiProof,
208 ) -> SparseStateTrieResult<()> {
209 let DecodedMultiProof {
210 account_subtree,
211 storages,
212 branch_node_hash_masks,
213 branch_node_tree_masks,
214 } = multiproof;
215
216 self.reveal_decoded_account_multiproof(
218 account_subtree,
219 branch_node_hash_masks,
220 branch_node_tree_masks,
221 )?;
222
223 #[cfg(not(feature = "std"))]
224 {
226 for (account, storage_subtree) in storages {
227 self.reveal_decoded_storage_multiproof(account, storage_subtree)?;
228 }
229
230 Ok(())
231 }
232
233 #[cfg(feature = "std")]
234 {
236 use rayon::iter::{ParallelBridge, ParallelIterator};
237
238 let (tx, rx) = std::sync::mpsc::channel();
239 let retain_updates = self.retain_updates;
240
241 storages
245 .into_iter()
246 .map(|(account, storage_subtree)| {
247 let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
248 let trie = self.storage.take_or_create_trie(&account);
249 (account, storage_subtree, revealed_nodes, trie)
250 })
251 .par_bridge()
252 .map(|(account, storage_subtree, mut revealed_nodes, mut trie)| {
253 let result = Self::reveal_decoded_storage_multiproof_inner(
254 account,
255 storage_subtree,
256 &mut revealed_nodes,
257 &mut trie,
258 retain_updates,
259 );
260
261 (account, revealed_nodes, trie, result)
262 })
263 .for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
264
265 drop(tx);
266
267 let mut any_err = Ok(());
270 for (account, revealed_nodes, trie, result) in rx {
271 self.storage.revealed_paths.insert(account, revealed_nodes);
272 self.storage.tries.insert(account, trie);
273 if let Ok(_metric_values) = result {
274 #[cfg(feature = "metrics")]
275 {
276 self.metrics
277 .increment_total_storage_nodes(_metric_values.total_nodes as u64);
278 self.metrics
279 .increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
280 }
281 } else {
282 any_err = result.map(|_| ());
283 }
284 }
285
286 any_err
287 }
288 }
289
290 pub fn reveal_account_multiproof(
292 &mut self,
293 account_subtree: ProofNodes,
294 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
295 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
296 ) -> SparseStateTrieResult<()> {
297 let decoded_multiproof = account_subtree.try_into()?;
299 self.reveal_decoded_account_multiproof(
300 decoded_multiproof,
301 branch_node_hash_masks,
302 branch_node_tree_masks,
303 )
304 }
305
306 pub fn reveal_decoded_account_multiproof(
308 &mut self,
309 account_subtree: DecodedProofNodes,
310 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
311 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
312 ) -> SparseStateTrieResult<()> {
313 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values: _metric_values } =
314 filter_map_revealed_nodes(
315 account_subtree,
316 &mut self.revealed_account_paths,
317 &branch_node_hash_masks,
318 &branch_node_tree_masks,
319 )?;
320 #[cfg(feature = "metrics")]
321 {
322 self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
323 self.metrics.increment_skipped_account_nodes(_metric_values.skipped_nodes as u64);
324 }
325
326 if let Some(root_node) = root_node {
327 trace!(target: "trie::sparse", ?root_node, "Revealing root account node");
329 let trie =
330 self.state.reveal_root(root_node.node, root_node.masks, self.retain_updates)?;
331
332 trie.reserve_nodes(new_nodes);
335
336 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes");
337 trie.reveal_nodes(nodes)?;
338 }
339
340 Ok(())
341 }
342
343 pub fn reveal_storage_multiproof(
345 &mut self,
346 account: B256,
347 storage_subtree: StorageMultiProof,
348 ) -> SparseStateTrieResult<()> {
349 let decoded_multiproof = storage_subtree.try_into()?;
351 self.reveal_decoded_storage_multiproof(account, decoded_multiproof)
352 }
353
354 pub fn reveal_decoded_storage_multiproof(
356 &mut self,
357 account: B256,
358 storage_subtree: DecodedStorageMultiProof,
359 ) -> SparseStateTrieResult<()> {
360 let (trie, revealed_paths) = self.storage.get_trie_and_revealed_paths_mut(account);
361 let _metric_values = Self::reveal_decoded_storage_multiproof_inner(
362 account,
363 storage_subtree,
364 revealed_paths,
365 trie,
366 self.retain_updates,
367 )?;
368
369 #[cfg(feature = "metrics")]
370 {
371 self.metrics.increment_total_storage_nodes(_metric_values.total_nodes as u64);
372 self.metrics.increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
373 }
374
375 Ok(())
376 }
377
378 fn reveal_decoded_storage_multiproof_inner(
381 account: B256,
382 storage_subtree: DecodedStorageMultiProof,
383 revealed_nodes: &mut HashSet<Nibbles>,
384 trie: &mut SparseTrie<S>,
385 retain_updates: bool,
386 ) -> SparseStateTrieResult<ProofNodesMetricValues> {
387 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values } =
388 filter_map_revealed_nodes(
389 storage_subtree.subtree,
390 revealed_nodes,
391 &storage_subtree.branch_node_hash_masks,
392 &storage_subtree.branch_node_tree_masks,
393 )?;
394
395 if let Some(root_node) = root_node {
396 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node");
398 let trie = trie.reveal_root(root_node.node, root_node.masks, retain_updates)?;
399
400 trie.reserve_nodes(new_nodes);
403
404 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes");
405 trie.reveal_nodes(nodes)?;
406 }
407
408 Ok(metric_values)
409 }
410
411 pub fn reveal_witness(
415 &mut self,
416 state_root: B256,
417 witness: &B256Map<Bytes>,
418 ) -> SparseStateTrieResult<()> {
419 let mut queue = VecDeque::from([(state_root, Nibbles::default(), None)]);
422
423 while let Some((hash, path, maybe_account)) = queue.pop_front() {
424 let Some(trie_node_bytes) = witness.get(&hash) else { continue };
426 let trie_node = TrieNode::decode(&mut &trie_node_bytes[..])?;
427
428 match &trie_node {
430 TrieNode::Branch(branch) => {
431 for (idx, maybe_child) in branch.as_ref().children() {
432 if let Some(child_hash) = maybe_child.and_then(RlpNode::as_hash) {
433 let mut child_path = path;
434 child_path.push_unchecked(idx);
435 queue.push_back((child_hash, child_path, maybe_account));
436 }
437 }
438 }
439 TrieNode::Extension(ext) => {
440 if let Some(child_hash) = ext.child.as_hash() {
441 let mut child_path = path;
442 child_path.extend(&ext.key);
443 queue.push_back((child_hash, child_path, maybe_account));
444 }
445 }
446 TrieNode::Leaf(leaf) => {
447 let mut full_path = path;
448 full_path.extend(&leaf.key);
449 if maybe_account.is_none() {
450 let hashed_address = B256::from_slice(&full_path.pack());
451 let account = TrieAccount::decode(&mut &leaf.value[..])?;
452 if account.storage_root != EMPTY_ROOT_HASH {
453 queue.push_back((
454 account.storage_root,
455 Nibbles::default(),
456 Some(hashed_address),
457 ));
458 }
459 }
460 }
461 TrieNode::EmptyRoot => {} };
463
464 if let Some(account) = maybe_account {
466 if self
468 .storage
469 .revealed_paths
470 .get(&account)
471 .is_none_or(|paths| !paths.contains(&path))
472 {
473 let retain_updates = self.retain_updates;
474 let (storage_trie_entry, revealed_storage_paths) =
475 self.storage.get_trie_and_revealed_paths_mut(account);
476
477 if path.is_empty() {
478 storage_trie_entry.reveal_root(
480 trie_node,
481 TrieMasks::none(),
482 retain_updates,
483 )?;
484 } else {
485 storage_trie_entry
487 .as_revealed_mut()
488 .ok_or(SparseTrieErrorKind::Blind)?
489 .reveal_node(path, trie_node, TrieMasks::none())?;
490 }
491
492 revealed_storage_paths.insert(path);
494 }
495 }
496 else if !self.revealed_account_paths.contains(&path) {
498 if path.is_empty() {
499 self.state.reveal_root(trie_node, TrieMasks::none(), self.retain_updates)?;
501 } else {
502 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?.reveal_node(
504 path,
505 trie_node,
506 TrieMasks::none(),
507 )?;
508 }
509
510 self.revealed_account_paths.insert(path);
512 }
513 }
514
515 Ok(())
516 }
517
518 pub fn wipe_storage(&mut self, address: B256) -> SparseStateTrieResult<()> {
520 if let Some(trie) = self.storage.tries.get_mut(&address) {
521 trie.wipe()?;
522 }
523 Ok(())
524 }
525
526 pub fn calculate_subtries(&mut self) {
530 if let SparseTrie::Revealed(trie) = &mut self.state {
531 trie.update_subtrie_hashes();
532 }
533 }
534
535 pub fn storage_root(&mut self, account: B256) -> Option<B256> {
537 self.storage.tries.get_mut(&account).and_then(|trie| trie.root())
538 }
539
540 fn revealed_trie_mut(
544 &mut self,
545 provider_factory: impl TrieNodeProviderFactory,
546 ) -> SparseStateTrieResult<&mut A> {
547 match self.state {
548 SparseTrie::Blind(_) => {
549 let (root_node, hash_mask, tree_mask) = provider_factory
550 .account_node_provider()
551 .trie_node(&Nibbles::default())?
552 .map(|node| {
553 TrieNode::decode(&mut &node.node[..])
554 .map(|decoded| (decoded, node.hash_mask, node.tree_mask))
555 })
556 .transpose()?
557 .unwrap_or((TrieNode::EmptyRoot, None, None));
558 self.state
559 .reveal_root(root_node, TrieMasks { hash_mask, tree_mask }, self.retain_updates)
560 .map_err(Into::into)
561 }
562 SparseTrie::Revealed(ref mut trie) => Ok(trie),
563 }
564 }
565
566 pub fn root(
570 &mut self,
571 provider_factory: impl TrieNodeProviderFactory,
572 ) -> SparseStateTrieResult<B256> {
573 #[cfg(feature = "metrics")]
575 self.metrics.record();
576
577 Ok(self.revealed_trie_mut(provider_factory)?.root())
578 }
579
580 pub fn root_with_updates(
582 &mut self,
583 provider_factory: impl TrieNodeProviderFactory,
584 ) -> SparseStateTrieResult<(B256, TrieUpdates)> {
585 #[cfg(feature = "metrics")]
587 self.metrics.record();
588
589 let storage_tries = self.storage_trie_updates();
590 let revealed = self.revealed_trie_mut(provider_factory)?;
591
592 let (root, updates) = (revealed.root(), revealed.take_updates());
593 let updates = TrieUpdates {
594 account_nodes: updates.updated_nodes,
595 removed_nodes: updates.removed_nodes,
596 storage_tries,
597 };
598 Ok((root, updates))
599 }
600
601 pub fn storage_trie_updates(&mut self) -> B256Map<StorageTrieUpdates> {
605 self.storage
606 .tries
607 .iter_mut()
608 .map(|(address, trie)| {
609 let trie = trie.as_revealed_mut().unwrap();
610 let updates = trie.take_updates();
611 let updates = StorageTrieUpdates {
612 is_deleted: updates.wiped,
613 storage_nodes: updates.updated_nodes,
614 removed_nodes: updates.removed_nodes,
615 };
616 (*address, updates)
617 })
618 .filter(|(_, updates)| !updates.is_empty())
619 .collect()
620 }
621
622 pub fn take_trie_updates(&mut self) -> Option<TrieUpdates> {
626 let storage_tries = self.storage_trie_updates();
627 self.state.as_revealed_mut().map(|state| {
628 let updates = state.take_updates();
629 TrieUpdates {
630 account_nodes: updates.updated_nodes,
631 removed_nodes: updates.removed_nodes,
632 storage_tries,
633 }
634 })
635 }
636
637 pub fn update_account_leaf(
639 &mut self,
640 path: Nibbles,
641 value: Vec<u8>,
642 provider_factory: impl TrieNodeProviderFactory,
643 ) -> SparseStateTrieResult<()> {
644 if !self.revealed_account_paths.contains(&path) {
645 self.revealed_account_paths.insert(path);
646 }
647
648 let provider = provider_factory.account_node_provider();
649 self.state.update_leaf(path, value, provider)?;
650 Ok(())
651 }
652
653 pub fn update_storage_leaf(
655 &mut self,
656 address: B256,
657 slot: Nibbles,
658 value: Vec<u8>,
659 provider_factory: impl TrieNodeProviderFactory,
660 ) -> SparseStateTrieResult<()> {
661 let provider = provider_factory.storage_node_provider(address);
662 self.storage
663 .tries
664 .get_mut(&address)
665 .ok_or(SparseTrieErrorKind::Blind)?
666 .update_leaf(slot, value, provider)?;
667 self.storage.get_revealed_paths_mut(address).insert(slot);
668 Ok(())
669 }
670
671 pub fn update_account(
677 &mut self,
678 address: B256,
679 account: Account,
680 provider_factory: impl TrieNodeProviderFactory,
681 ) -> SparseStateTrieResult<bool> {
682 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
683 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
684 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
685 } else if self.is_account_revealed(address) {
686 trace!(target: "trie::sparse", ?address, "Retrieving storage root from account leaf to update account");
687 if let Some(value) = self.get_account_value(&address) {
689 TrieAccount::decode(&mut &value[..])?.storage_root
691 } else {
692 EMPTY_ROOT_HASH
694 }
695 } else {
696 return Err(SparseTrieErrorKind::Blind.into())
697 };
698
699 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
700 return Ok(false);
701 }
702
703 trace!(target: "trie::sparse", ?address, "Updating account");
704 let nibbles = Nibbles::unpack(address);
705 self.account_rlp_buf.clear();
706 account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
707 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
708
709 Ok(true)
710 }
711
712 pub fn update_account_storage_root(
719 &mut self,
720 address: B256,
721 provider_factory: impl TrieNodeProviderFactory,
722 ) -> SparseStateTrieResult<bool> {
723 if !self.is_account_revealed(address) {
724 return Err(SparseTrieErrorKind::Blind.into())
725 }
726
727 let Some(mut trie_account) = self
729 .get_account_value(&address)
730 .map(|v| TrieAccount::decode(&mut &v[..]))
731 .transpose()?
732 else {
733 trace!(target: "trie::sparse", ?address, "Account not found in trie, skipping storage root update");
734 return Ok(true)
735 };
736
737 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
740 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
741 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
742 } else {
743 EMPTY_ROOT_HASH
744 };
745
746 trie_account.storage_root = storage_root;
748
749 if trie_account == TrieAccount::default() {
751 return Ok(false)
752 }
753
754 trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
756 let nibbles = Nibbles::unpack(address);
757 self.account_rlp_buf.clear();
758 trie_account.encode(&mut self.account_rlp_buf);
759 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
760
761 Ok(true)
762 }
763
764 pub fn remove_account_leaf(
766 &mut self,
767 path: &Nibbles,
768 provider_factory: impl TrieNodeProviderFactory,
769 ) -> SparseStateTrieResult<()> {
770 let provider = provider_factory.account_node_provider();
771 self.state.remove_leaf(path, provider)?;
772 Ok(())
773 }
774
775 pub fn remove_storage_leaf(
777 &mut self,
778 address: B256,
779 slot: &Nibbles,
780 provider_factory: impl TrieNodeProviderFactory,
781 ) -> SparseStateTrieResult<()> {
782 let storage_trie =
783 self.storage.tries.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
784
785 let provider = provider_factory.storage_node_provider(address);
786 storage_trie.remove_leaf(slot, provider)?;
787 Ok(())
788 }
789}
790
791#[derive(Debug, Default)]
795struct StorageTries<S = SerialSparseTrie> {
796 tries: B256Map<SparseTrie<S>>,
798 cleared_tries: Vec<SparseTrie<S>>,
800 revealed_paths: B256Map<HashSet<Nibbles>>,
802 cleared_revealed_paths: Vec<HashSet<Nibbles>>,
804}
805
806impl<S: SparseTrieInterface + Default> StorageTries<S> {
807 fn clear(&mut self) {
810 self.cleared_tries.extend(self.tries.drain().map(|(_, trie)| trie.clear()));
811 self.cleared_revealed_paths.extend(self.revealed_paths.drain().map(|(_, mut set)| {
812 set.clear();
813 set
814 }));
815 }
816
817 fn get_revealed_paths_mut(&mut self, account: B256) -> &mut HashSet<Nibbles> {
820 self.revealed_paths
821 .entry(account)
822 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default())
823 }
824
825 fn get_trie_and_revealed_paths_mut(
828 &mut self,
829 account: B256,
830 ) -> (&mut SparseTrie<S>, &mut HashSet<Nibbles>) {
831 let trie = self
832 .tries
833 .entry(account)
834 .or_insert_with(|| self.cleared_tries.pop().unwrap_or_default());
835
836 let revealed_paths = self
837 .revealed_paths
838 .entry(account)
839 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default());
840
841 (trie, revealed_paths)
842 }
843
844 #[cfg(feature = "std")]
847 fn take_or_create_trie(&mut self, account: &B256) -> SparseTrie<S> {
848 self.tries.remove(account).unwrap_or_else(|| self.cleared_tries.pop().unwrap_or_default())
849 }
850
851 #[cfg(feature = "std")]
854 fn take_or_create_revealed_paths(&mut self, account: &B256) -> HashSet<Nibbles> {
855 self.revealed_paths
856 .remove(account)
857 .unwrap_or_else(|| self.cleared_revealed_paths.pop().unwrap_or_default())
858 }
859}
860
861#[derive(Debug, PartialEq, Eq, Default)]
862struct ProofNodesMetricValues {
863 total_nodes: usize,
865 skipped_nodes: usize,
867}
868
869#[derive(Debug, PartialEq, Eq)]
871struct FilterMappedProofNodes {
872 root_node: Option<RevealedSparseNode>,
874 nodes: Vec<RevealedSparseNode>,
876 new_nodes: usize,
879 metric_values: ProofNodesMetricValues,
881}
882
883fn filter_map_revealed_nodes(
887 proof_nodes: DecodedProofNodes,
888 revealed_nodes: &mut HashSet<Nibbles>,
889 branch_node_hash_masks: &HashMap<Nibbles, TrieMask>,
890 branch_node_tree_masks: &HashMap<Nibbles, TrieMask>,
891) -> SparseStateTrieResult<FilterMappedProofNodes> {
892 let mut result = FilterMappedProofNodes {
893 root_node: None,
894 nodes: Vec::with_capacity(proof_nodes.len()),
895 new_nodes: 0,
896 metric_values: Default::default(),
897 };
898
899 let proof_nodes_len = proof_nodes.len();
900 for (path, proof_node) in proof_nodes.into_inner() {
901 result.metric_values.total_nodes += 1;
902
903 let is_root = path.is_empty();
904
905 if !is_root && !revealed_nodes.insert(path) {
908 result.metric_values.skipped_nodes += 1;
909 continue
910 }
911
912 result.new_nodes += 1;
913
914 let masks = match &proof_node {
917 TrieNode::Branch(branch) => {
918 result.new_nodes += branch.state_mask.count_ones() as usize;
921 TrieMasks {
922 hash_mask: branch_node_hash_masks.get(&path).copied(),
923 tree_mask: branch_node_tree_masks.get(&path).copied(),
924 }
925 }
926 TrieNode::Extension(_) => {
927 result.new_nodes += 1;
929 TrieMasks::none()
930 }
931 _ => TrieMasks::none(),
932 };
933
934 let node = RevealedSparseNode { path, node: proof_node, masks };
935
936 if is_root {
937 if matches!(node.node, TrieNode::EmptyRoot) && proof_nodes_len > 1 {
939 return Err(SparseStateTrieErrorKind::InvalidRootNode {
940 path,
941 node: alloy_rlp::encode(&node.node).into(),
942 }
943 .into())
944 }
945
946 result.root_node = Some(node);
947
948 continue
949 }
950
951 result.nodes.push(node);
952 }
953
954 Ok(result)
955}
956
957#[cfg(test)]
958mod tests {
959 use super::*;
960 use crate::provider::DefaultTrieNodeProviderFactory;
961 use alloy_primitives::{
962 b256,
963 map::{HashMap, HashSet},
964 U256,
965 };
966 use arbitrary::Arbitrary;
967 use rand::{rngs::StdRng, Rng, SeedableRng};
968 use reth_primitives_traits::Account;
969 use reth_trie::{updates::StorageTrieUpdates, HashBuilder, MultiProof, EMPTY_ROOT_HASH};
970 use reth_trie_common::{
971 proof::{ProofNodes, ProofRetainer},
972 BranchNode, LeafNode, StorageMultiProof, TrieMask,
973 };
974
975 #[test]
976 fn reveal_account_path_twice() {
977 let provider_factory = DefaultTrieNodeProviderFactory;
978 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
979
980 let leaf_value = alloy_rlp::encode(TrieAccount::default());
981 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
982 Nibbles::default(),
983 leaf_value.clone(),
984 )));
985 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
986 Nibbles::default(),
987 leaf_value.clone(),
988 )));
989
990 let multiproof = MultiProof {
991 account_subtree: ProofNodes::from_iter([
992 (
993 Nibbles::default(),
994 alloy_rlp::encode(TrieNode::Branch(BranchNode {
995 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
996 state_mask: TrieMask::new(0b11),
997 }))
998 .into(),
999 ),
1000 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1001 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1002 ]),
1003 ..Default::default()
1004 };
1005
1006 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1008 assert!(sparse
1009 .state_trie_ref()
1010 .unwrap()
1011 .nodes_ref()
1012 .contains_key(&Nibbles::from_nibbles([0x0])),);
1013 assert_eq!(
1014 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
1015 Some(&leaf_value)
1016 );
1017
1018 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &provider_factory).unwrap();
1021 assert!(!sparse
1022 .state_trie_ref()
1023 .unwrap()
1024 .nodes_ref()
1025 .contains_key(&Nibbles::from_nibbles([0x0])),);
1026 assert!(sparse
1027 .state_trie_ref()
1028 .unwrap()
1029 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1030 .is_none());
1031
1032 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1035 assert!(!sparse
1036 .state_trie_ref()
1037 .unwrap()
1038 .nodes_ref()
1039 .contains_key(&Nibbles::from_nibbles([0x0])));
1040 assert!(sparse
1041 .state_trie_ref()
1042 .unwrap()
1043 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1044 .is_none());
1045 }
1046
1047 #[test]
1048 fn reveal_storage_path_twice() {
1049 let provider_factory = DefaultTrieNodeProviderFactory;
1050 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
1051
1052 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1053 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1054 Nibbles::default(),
1055 leaf_value.clone(),
1056 )));
1057 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1058 Nibbles::default(),
1059 leaf_value.clone(),
1060 )));
1061
1062 let multiproof = MultiProof {
1063 storages: HashMap::from_iter([(
1064 B256::ZERO,
1065 StorageMultiProof {
1066 root: B256::ZERO,
1067 subtree: ProofNodes::from_iter([
1068 (
1069 Nibbles::default(),
1070 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1071 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1072 state_mask: TrieMask::new(0b11),
1073 }))
1074 .into(),
1075 ),
1076 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1077 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1078 ]),
1079 branch_node_hash_masks: Default::default(),
1080 branch_node_tree_masks: Default::default(),
1081 },
1082 )]),
1083 ..Default::default()
1084 };
1085
1086 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1088 assert!(sparse
1089 .storage_trie_ref(&B256::ZERO)
1090 .unwrap()
1091 .nodes_ref()
1092 .contains_key(&Nibbles::from_nibbles([0x0])),);
1093 assert_eq!(
1094 sparse
1095 .storage_trie_ref(&B256::ZERO)
1096 .unwrap()
1097 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
1098 Some(&leaf_value)
1099 );
1100
1101 sparse
1104 .remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0]), &provider_factory)
1105 .unwrap();
1106 assert!(!sparse
1107 .storage_trie_ref(&B256::ZERO)
1108 .unwrap()
1109 .nodes_ref()
1110 .contains_key(&Nibbles::from_nibbles([0x0])),);
1111 assert!(sparse
1112 .storage_trie_ref(&B256::ZERO)
1113 .unwrap()
1114 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1115 .is_none());
1116
1117 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1120 assert!(!sparse
1121 .storage_trie_ref(&B256::ZERO)
1122 .unwrap()
1123 .nodes_ref()
1124 .contains_key(&Nibbles::from_nibbles([0x0])));
1125 assert!(sparse
1126 .storage_trie_ref(&B256::ZERO)
1127 .unwrap()
1128 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1129 .is_none());
1130 }
1131
1132 #[test]
1133 fn take_trie_updates() {
1134 reth_tracing::init_test_tracing();
1135
1136 let mut rng = StdRng::seed_from_u64(1);
1138
1139 let mut bytes = [0u8; 1024];
1140 rng.fill(bytes.as_mut_slice());
1141
1142 let slot_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1143 let slot_path_1 = Nibbles::unpack(slot_1);
1144 let value_1 = U256::from(rng.random::<u64>());
1145 let slot_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1146 let slot_path_2 = Nibbles::unpack(slot_2);
1147 let value_2 = U256::from(rng.random::<u64>());
1148 let slot_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1149 let slot_path_3 = Nibbles::unpack(slot_3);
1150 let value_3 = U256::from(rng.random::<u64>());
1151
1152 let mut storage_hash_builder = HashBuilder::default()
1153 .with_proof_retainer(ProofRetainer::from_iter([slot_path_1, slot_path_2]));
1154 storage_hash_builder.add_leaf(slot_path_1, &alloy_rlp::encode_fixed_size(&value_1));
1155 storage_hash_builder.add_leaf(slot_path_2, &alloy_rlp::encode_fixed_size(&value_2));
1156
1157 let storage_root = storage_hash_builder.root();
1158 let storage_proof_nodes = storage_hash_builder.take_proof_nodes();
1159 let storage_branch_node_hash_masks = HashMap::from_iter([
1160 (Nibbles::default(), TrieMask::new(0b010)),
1161 (Nibbles::from_nibbles([0x1]), TrieMask::new(0b11)),
1162 ]);
1163
1164 let address_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1165 let address_path_1 = Nibbles::unpack(address_1);
1166 let account_1 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1167 let mut trie_account_1 = account_1.into_trie_account(storage_root);
1168 let address_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1169 let address_path_2 = Nibbles::unpack(address_2);
1170 let account_2 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1171 let mut trie_account_2 = account_2.into_trie_account(EMPTY_ROOT_HASH);
1172
1173 let mut hash_builder = HashBuilder::default()
1174 .with_proof_retainer(ProofRetainer::from_iter([address_path_1, address_path_2]));
1175 hash_builder.add_leaf(address_path_1, &alloy_rlp::encode(trie_account_1));
1176 hash_builder.add_leaf(address_path_2, &alloy_rlp::encode(trie_account_2));
1177
1178 let root = hash_builder.root();
1179 let proof_nodes = hash_builder.take_proof_nodes();
1180
1181 let provider_factory = DefaultTrieNodeProviderFactory;
1182 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default().with_updates(true);
1183 sparse
1184 .reveal_decoded_multiproof(
1185 MultiProof {
1186 account_subtree: proof_nodes,
1187 branch_node_hash_masks: HashMap::from_iter([(
1188 Nibbles::from_nibbles([0x1]),
1189 TrieMask::new(0b00),
1190 )]),
1191 branch_node_tree_masks: HashMap::default(),
1192 storages: HashMap::from_iter([
1193 (
1194 address_1,
1195 StorageMultiProof {
1196 root,
1197 subtree: storage_proof_nodes.clone(),
1198 branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
1199 branch_node_tree_masks: HashMap::default(),
1200 },
1201 ),
1202 (
1203 address_2,
1204 StorageMultiProof {
1205 root,
1206 subtree: storage_proof_nodes,
1207 branch_node_hash_masks: storage_branch_node_hash_masks,
1208 branch_node_tree_masks: HashMap::default(),
1209 },
1210 ),
1211 ]),
1212 }
1213 .try_into()
1214 .unwrap(),
1215 )
1216 .unwrap();
1217
1218 assert_eq!(sparse.root(&provider_factory).unwrap(), root);
1219
1220 let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1221 let address_path_3 = Nibbles::unpack(address_3);
1222 let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
1223 let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
1224
1225 sparse
1226 .update_account_leaf(
1227 address_path_3,
1228 alloy_rlp::encode(trie_account_3),
1229 &provider_factory,
1230 )
1231 .unwrap();
1232
1233 sparse
1234 .update_storage_leaf(
1235 address_1,
1236 slot_path_3,
1237 alloy_rlp::encode(value_3),
1238 &provider_factory,
1239 )
1240 .unwrap();
1241 trie_account_1.storage_root = sparse.storage_root(address_1).unwrap();
1242 sparse
1243 .update_account_leaf(
1244 address_path_1,
1245 alloy_rlp::encode(trie_account_1),
1246 &provider_factory,
1247 )
1248 .unwrap();
1249
1250 sparse.wipe_storage(address_2).unwrap();
1251 trie_account_2.storage_root = sparse.storage_root(address_2).unwrap();
1252 sparse
1253 .update_account_leaf(
1254 address_path_2,
1255 alloy_rlp::encode(trie_account_2),
1256 &provider_factory,
1257 )
1258 .unwrap();
1259
1260 sparse.root(&provider_factory).unwrap();
1261
1262 let sparse_updates = sparse.take_trie_updates().unwrap();
1263 pretty_assertions::assert_eq!(
1265 sparse_updates,
1266 TrieUpdates {
1267 account_nodes: HashMap::default(),
1268 storage_tries: HashMap::from_iter([(
1269 b256!("0x1100000000000000000000000000000000000000000000000000000000000000"),
1270 StorageTrieUpdates {
1271 is_deleted: true,
1272 storage_nodes: HashMap::default(),
1273 removed_nodes: HashSet::default()
1274 }
1275 )]),
1276 removed_nodes: HashSet::default()
1277 }
1278 );
1279 }
1280
1281 #[test]
1282 fn test_filter_map_revealed_nodes() {
1283 let mut revealed_nodes = HashSet::from_iter([Nibbles::from_nibbles([0x0])]);
1284 let leaf = TrieNode::Leaf(LeafNode::new(Nibbles::default(), alloy_rlp::encode([])));
1285 let leaf_encoded = alloy_rlp::encode(&leaf);
1286 let branch = TrieNode::Branch(BranchNode::new(
1287 vec![RlpNode::from_rlp(&leaf_encoded), RlpNode::from_rlp(&leaf_encoded)],
1288 TrieMask::new(0b11),
1289 ));
1290 let proof_nodes = alloy_trie::proof::DecodedProofNodes::from_iter([
1291 (Nibbles::default(), branch.clone()),
1292 (Nibbles::from_nibbles([0x0]), leaf.clone()),
1293 (Nibbles::from_nibbles([0x1]), leaf.clone()),
1294 ]);
1295
1296 let branch_node_hash_masks = HashMap::default();
1297 let branch_node_tree_masks = HashMap::default();
1298
1299 let decoded = filter_map_revealed_nodes(
1300 proof_nodes,
1301 &mut revealed_nodes,
1302 &branch_node_hash_masks,
1303 &branch_node_tree_masks,
1304 )
1305 .unwrap();
1306
1307 assert_eq!(
1308 decoded,
1309 FilterMappedProofNodes {
1310 root_node: Some(RevealedSparseNode {
1311 path: Nibbles::default(),
1312 node: branch,
1313 masks: TrieMasks::none(),
1314 }),
1315 nodes: vec![RevealedSparseNode {
1316 path: Nibbles::from_nibbles([0x1]),
1317 node: leaf,
1318 masks: TrieMasks::none(),
1319 }],
1320 new_nodes: 4,
1322 metric_values: ProofNodesMetricValues {
1324 total_nodes: 3,
1326 skipped_nodes: 1,
1328 },
1329 }
1330 );
1331 }
1332}