1use crate::{
2 provider::{TrieNodeProvider, TrieNodeProviderFactory},
3 traits::SparseTrieInterface,
4 SerialSparseTrie, SparseTrie,
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, ProofTrieNode, RlpNode,
19 StorageMultiProof, TrieAccount, TrieMask, TrieMasks, TrieNode, EMPTY_ROOT_HASH,
20 TRIE_ACCOUNT_RLP_MAX_SIZE,
21};
22use tracing::{instrument, trace};
23
24#[derive(Debug)]
27pub struct ClearedSparseStateTrie<
28 A = SerialSparseTrie, S = SerialSparseTrie, >(SparseStateTrie<A, S>);
31
32impl<A, S> ClearedSparseStateTrie<A, S>
33where
34 A: SparseTrieInterface,
35 S: SparseTrieInterface,
36{
37 pub fn from_state_trie(mut trie: SparseStateTrie<A, S>) -> Self {
40 trie.state = trie.state.clear();
41 trie.revealed_account_paths.clear();
42 trie.storage.clear();
43 trie.account_rlp_buf.clear();
44 Self(trie)
45 }
46
47 pub fn shrink_to(&mut self, node_size: usize, value_size: usize) {
51 let storage_tries_count = self.0.storage.tries.len() + self.0.storage.cleared_tries.len();
53
54 let total_tries = 1 + storage_tries_count;
56
57 let node_size_per_trie = node_size / total_tries;
59 let value_size_per_trie = value_size / total_tries;
60
61 self.0.state.shrink_nodes_to(node_size_per_trie);
63 self.0.state.shrink_values_to(value_size_per_trie);
64
65 let storage_node_size = node_size.saturating_sub(node_size_per_trie);
67 let storage_value_size = value_size.saturating_sub(value_size_per_trie);
68
69 self.0.storage.shrink_to(storage_node_size, storage_value_size);
71 }
72
73 pub fn into_inner(self) -> SparseStateTrie<A, S> {
75 self.0
76 }
77}
78
79#[derive(Debug)]
80pub struct SparseStateTrie<
82 A = SerialSparseTrie, S = SerialSparseTrie, > {
85 state: SparseTrie<A>,
87 revealed_account_paths: HashSet<Nibbles>,
89 storage: StorageTries<S>,
91 retain_updates: bool,
93 account_rlp_buf: Vec<u8>,
95 #[cfg(feature = "metrics")]
97 metrics: crate::metrics::SparseStateTrieMetrics,
98}
99
100impl<A, S> Default for SparseStateTrie<A, S>
101where
102 A: Default,
103 S: Default,
104{
105 fn default() -> Self {
106 Self {
107 state: Default::default(),
108 revealed_account_paths: Default::default(),
109 storage: Default::default(),
110 retain_updates: false,
111 account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
112 #[cfg(feature = "metrics")]
113 metrics: Default::default(),
114 }
115 }
116}
117
118#[cfg(test)]
119impl SparseStateTrie {
120 pub fn from_state(state: SparseTrie) -> Self {
122 Self { state, ..Default::default() }
123 }
124}
125
126impl<A, S> SparseStateTrie<A, S> {
127 pub const fn with_updates(mut self, retain_updates: bool) -> Self {
129 self.retain_updates = retain_updates;
130 self
131 }
132
133 pub fn with_accounts_trie(mut self, trie: SparseTrie<A>) -> Self {
135 self.state = trie;
136 self
137 }
138
139 pub fn with_default_storage_trie(mut self, trie: SparseTrie<S>) -> Self {
141 self.storage.default_trie = trie;
142 self
143 }
144}
145
146impl<A, S> SparseStateTrie<A, S>
147where
148 A: SparseTrieInterface + Default,
149 S: SparseTrieInterface + Default + Clone,
150{
151 pub fn new() -> Self {
153 Self::default()
154 }
155
156 pub fn is_account_revealed(&self, account: B256) -> bool {
158 self.revealed_account_paths.contains(&Nibbles::unpack(account))
159 }
160
161 pub fn check_valid_account_witness(&self, address: B256) -> bool {
163 let path = Nibbles::unpack(address);
164 let trie = match self.state_trie_ref() {
165 Some(t) => t,
166 None => return false,
167 };
168
169 trie.find_leaf(&path, None).is_ok()
170 }
171
172 pub fn check_valid_storage_witness(&self, address: B256, slot: B256) -> bool {
174 let path = Nibbles::unpack(slot);
175 let trie = match self.storage_trie_ref(&address) {
176 Some(t) => t,
177 None => return false,
178 };
179
180 trie.find_leaf(&path, None).is_ok()
181 }
182
183 pub fn is_storage_slot_revealed(&self, account: B256, slot: B256) -> bool {
185 self.storage
186 .revealed_paths
187 .get(&account)
188 .is_some_and(|slots| slots.contains(&Nibbles::unpack(slot)))
189 }
190
191 pub fn get_account_value(&self, account: &B256) -> Option<&Vec<u8>> {
193 self.state.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(account))
194 }
195
196 pub fn get_storage_slot_value(&self, account: &B256, slot: &B256) -> Option<&Vec<u8>> {
198 self.storage.tries.get(account)?.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(slot))
199 }
200
201 pub const fn state_trie_ref(&self) -> Option<&A> {
203 self.state.as_revealed_ref()
204 }
205
206 pub fn storage_trie_ref(&self, address: &B256) -> Option<&S> {
208 self.storage.tries.get(address).and_then(|e| e.as_revealed_ref())
209 }
210
211 pub fn storage_trie_mut(&mut self, address: &B256) -> Option<&mut S> {
213 self.storage.tries.get_mut(address).and_then(|e| e.as_revealed_mut())
214 }
215
216 pub fn take_storage_trie(&mut self, address: &B256) -> Option<SparseTrie<S>> {
218 self.storage.tries.remove(address)
219 }
220
221 pub fn insert_storage_trie(&mut self, address: B256, storage_trie: SparseTrie<S>) {
223 self.storage.tries.insert(address, storage_trie);
224 }
225
226 pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
229 let decoded_multiproof = multiproof.try_into()?;
231
232 self.reveal_decoded_multiproof(decoded_multiproof)
234 }
235
236 #[instrument(
239 target = "trie::sparse",
240 skip_all,
241 fields(
242 account_nodes = multiproof.account_subtree.len(),
243 storages = multiproof.storages.len()
244 )
245 )]
246 pub fn reveal_decoded_multiproof(
247 &mut self,
248 multiproof: DecodedMultiProof,
249 ) -> SparseStateTrieResult<()> {
250 let DecodedMultiProof {
251 account_subtree,
252 storages,
253 branch_node_hash_masks,
254 branch_node_tree_masks,
255 } = multiproof;
256
257 self.reveal_decoded_account_multiproof(
259 account_subtree,
260 branch_node_hash_masks,
261 branch_node_tree_masks,
262 )?;
263
264 #[cfg(not(feature = "std"))]
265 {
267 for (account, storage_subtree) in storages {
268 self.reveal_decoded_storage_multiproof(account, storage_subtree)?;
269 }
270
271 Ok(())
272 }
273
274 #[cfg(feature = "std")]
275 {
277 use rayon::iter::{ParallelBridge, ParallelIterator};
278
279 let (tx, rx) = std::sync::mpsc::channel();
280 let retain_updates = self.retain_updates;
281
282 storages
286 .into_iter()
287 .map(|(account, storage_subtree)| {
288 let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
289 let trie = self.storage.take_or_create_trie(&account);
290 (account, storage_subtree, revealed_nodes, trie)
291 })
292 .par_bridge()
293 .map(|(account, storage_subtree, mut revealed_nodes, mut trie)| {
294 let result = Self::reveal_decoded_storage_multiproof_inner(
295 account,
296 storage_subtree,
297 &mut revealed_nodes,
298 &mut trie,
299 retain_updates,
300 );
301
302 (account, revealed_nodes, trie, result)
303 })
304 .for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
305
306 drop(tx);
307
308 let mut any_err = Ok(());
311 for (account, revealed_nodes, trie, result) in rx {
312 self.storage.revealed_paths.insert(account, revealed_nodes);
313 self.storage.tries.insert(account, trie);
314 if let Ok(_metric_values) = result {
315 #[cfg(feature = "metrics")]
316 {
317 self.metrics
318 .increment_total_storage_nodes(_metric_values.total_nodes as u64);
319 self.metrics
320 .increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
321 }
322 } else {
323 any_err = result.map(|_| ());
324 }
325 }
326
327 any_err
328 }
329 }
330
331 pub fn reveal_account_multiproof(
333 &mut self,
334 account_subtree: ProofNodes,
335 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
336 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
337 ) -> SparseStateTrieResult<()> {
338 let decoded_multiproof = account_subtree.try_into()?;
340 self.reveal_decoded_account_multiproof(
341 decoded_multiproof,
342 branch_node_hash_masks,
343 branch_node_tree_masks,
344 )
345 }
346
347 pub fn reveal_decoded_account_multiproof(
349 &mut self,
350 account_subtree: DecodedProofNodes,
351 branch_node_hash_masks: HashMap<Nibbles, TrieMask>,
352 branch_node_tree_masks: HashMap<Nibbles, TrieMask>,
353 ) -> SparseStateTrieResult<()> {
354 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values: _metric_values } =
355 filter_map_revealed_nodes(
356 account_subtree,
357 &mut self.revealed_account_paths,
358 &branch_node_hash_masks,
359 &branch_node_tree_masks,
360 )?;
361 #[cfg(feature = "metrics")]
362 {
363 self.metrics.increment_total_account_nodes(_metric_values.total_nodes as u64);
364 self.metrics.increment_skipped_account_nodes(_metric_values.skipped_nodes as u64);
365 }
366
367 if let Some(root_node) = root_node {
368 trace!(target: "trie::sparse", ?root_node, "Revealing root account node");
370 let trie =
371 self.state.reveal_root(root_node.node, root_node.masks, self.retain_updates)?;
372
373 trie.reserve_nodes(new_nodes);
376
377 trace!(target: "trie::sparse", total_nodes = ?nodes.len(), "Revealing account nodes");
378 trie.reveal_nodes(nodes)?;
379 }
380
381 Ok(())
382 }
383
384 pub fn reveal_storage_multiproof(
386 &mut self,
387 account: B256,
388 storage_subtree: StorageMultiProof,
389 ) -> SparseStateTrieResult<()> {
390 let decoded_multiproof = storage_subtree.try_into()?;
392 self.reveal_decoded_storage_multiproof(account, decoded_multiproof)
393 }
394
395 pub fn reveal_decoded_storage_multiproof(
397 &mut self,
398 account: B256,
399 storage_subtree: DecodedStorageMultiProof,
400 ) -> SparseStateTrieResult<()> {
401 let (trie, revealed_paths) = self.storage.get_trie_and_revealed_paths_mut(account);
402 let _metric_values = Self::reveal_decoded_storage_multiproof_inner(
403 account,
404 storage_subtree,
405 revealed_paths,
406 trie,
407 self.retain_updates,
408 )?;
409
410 #[cfg(feature = "metrics")]
411 {
412 self.metrics.increment_total_storage_nodes(_metric_values.total_nodes as u64);
413 self.metrics.increment_skipped_storage_nodes(_metric_values.skipped_nodes as u64);
414 }
415
416 Ok(())
417 }
418
419 fn reveal_decoded_storage_multiproof_inner(
422 account: B256,
423 storage_subtree: DecodedStorageMultiProof,
424 revealed_nodes: &mut HashSet<Nibbles>,
425 trie: &mut SparseTrie<S>,
426 retain_updates: bool,
427 ) -> SparseStateTrieResult<ProofNodesMetricValues> {
428 let FilterMappedProofNodes { root_node, nodes, new_nodes, metric_values } =
429 filter_map_revealed_nodes(
430 storage_subtree.subtree,
431 revealed_nodes,
432 &storage_subtree.branch_node_hash_masks,
433 &storage_subtree.branch_node_tree_masks,
434 )?;
435
436 if let Some(root_node) = root_node {
437 trace!(target: "trie::sparse", ?account, ?root_node, "Revealing root storage node");
439 let trie = trie.reveal_root(root_node.node, root_node.masks, retain_updates)?;
440
441 trie.reserve_nodes(new_nodes);
444
445 trace!(target: "trie::sparse", ?account, total_nodes = ?nodes.len(), "Revealing storage nodes");
446 trie.reveal_nodes(nodes)?;
447 }
448
449 Ok(metric_values)
450 }
451
452 pub fn reveal_witness(
456 &mut self,
457 state_root: B256,
458 witness: &B256Map<Bytes>,
459 ) -> SparseStateTrieResult<()> {
460 let mut queue = VecDeque::from([(state_root, Nibbles::default(), None)]);
463
464 while let Some((hash, path, maybe_account)) = queue.pop_front() {
465 let Some(trie_node_bytes) = witness.get(&hash) else { continue };
467 let trie_node = TrieNode::decode(&mut &trie_node_bytes[..])?;
468
469 match &trie_node {
471 TrieNode::Branch(branch) => {
472 for (idx, maybe_child) in branch.as_ref().children() {
473 if let Some(child_hash) = maybe_child.and_then(RlpNode::as_hash) {
474 let mut child_path = path;
475 child_path.push_unchecked(idx);
476 queue.push_back((child_hash, child_path, maybe_account));
477 }
478 }
479 }
480 TrieNode::Extension(ext) => {
481 if let Some(child_hash) = ext.child.as_hash() {
482 let mut child_path = path;
483 child_path.extend(&ext.key);
484 queue.push_back((child_hash, child_path, maybe_account));
485 }
486 }
487 TrieNode::Leaf(leaf) => {
488 let mut full_path = path;
489 full_path.extend(&leaf.key);
490 if maybe_account.is_none() {
491 let hashed_address = B256::from_slice(&full_path.pack());
492 let account = TrieAccount::decode(&mut &leaf.value[..])?;
493 if account.storage_root != EMPTY_ROOT_HASH {
494 queue.push_back((
495 account.storage_root,
496 Nibbles::default(),
497 Some(hashed_address),
498 ));
499 }
500 }
501 }
502 TrieNode::EmptyRoot => {} };
504
505 if let Some(account) = maybe_account {
507 if self
509 .storage
510 .revealed_paths
511 .get(&account)
512 .is_none_or(|paths| !paths.contains(&path))
513 {
514 let retain_updates = self.retain_updates;
515 let (storage_trie_entry, revealed_storage_paths) =
516 self.storage.get_trie_and_revealed_paths_mut(account);
517
518 if path.is_empty() {
519 storage_trie_entry.reveal_root(
521 trie_node,
522 TrieMasks::none(),
523 retain_updates,
524 )?;
525 } else {
526 storage_trie_entry
528 .as_revealed_mut()
529 .ok_or(SparseTrieErrorKind::Blind)?
530 .reveal_node(path, trie_node, TrieMasks::none())?;
531 }
532
533 revealed_storage_paths.insert(path);
535 }
536 }
537 else if !self.revealed_account_paths.contains(&path) {
539 if path.is_empty() {
540 self.state.reveal_root(trie_node, TrieMasks::none(), self.retain_updates)?;
542 } else {
543 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?.reveal_node(
545 path,
546 trie_node,
547 TrieMasks::none(),
548 )?;
549 }
550
551 self.revealed_account_paths.insert(path);
553 }
554 }
555
556 Ok(())
557 }
558
559 pub fn wipe_storage(&mut self, address: B256) -> SparseStateTrieResult<()> {
561 if let Some(trie) = self.storage.tries.get_mut(&address) {
562 trie.wipe()?;
563 }
564 Ok(())
565 }
566
567 #[instrument(target = "trie::sparse", skip_all)]
571 pub fn calculate_subtries(&mut self) {
572 if let SparseTrie::Revealed(trie) = &mut self.state {
573 trie.update_subtrie_hashes();
574 }
575 }
576
577 pub fn storage_root(&mut self, account: B256) -> Option<B256> {
579 self.storage.tries.get_mut(&account).and_then(|trie| trie.root())
580 }
581
582 fn revealed_trie_mut(
586 &mut self,
587 provider_factory: impl TrieNodeProviderFactory,
588 ) -> SparseStateTrieResult<&mut A> {
589 match self.state {
590 SparseTrie::Blind(_) => {
591 let (root_node, hash_mask, tree_mask) = provider_factory
592 .account_node_provider()
593 .trie_node(&Nibbles::default())?
594 .map(|node| {
595 TrieNode::decode(&mut &node.node[..])
596 .map(|decoded| (decoded, node.hash_mask, node.tree_mask))
597 })
598 .transpose()?
599 .unwrap_or((TrieNode::EmptyRoot, None, None));
600 self.state
601 .reveal_root(root_node, TrieMasks { hash_mask, tree_mask }, self.retain_updates)
602 .map_err(Into::into)
603 }
604 SparseTrie::Revealed(ref mut trie) => Ok(trie),
605 }
606 }
607
608 pub fn root(
612 &mut self,
613 provider_factory: impl TrieNodeProviderFactory,
614 ) -> SparseStateTrieResult<B256> {
615 #[cfg(feature = "metrics")]
617 self.metrics.record();
618
619 Ok(self.revealed_trie_mut(provider_factory)?.root())
620 }
621
622 #[instrument(target = "trie::sparse", skip_all)]
624 pub fn root_with_updates(
625 &mut self,
626 provider_factory: impl TrieNodeProviderFactory,
627 ) -> SparseStateTrieResult<(B256, TrieUpdates)> {
628 #[cfg(feature = "metrics")]
630 self.metrics.record();
631
632 let storage_tries = self.storage_trie_updates();
633 let revealed = self.revealed_trie_mut(provider_factory)?;
634
635 let (root, updates) = (revealed.root(), revealed.take_updates());
636 let updates = TrieUpdates {
637 account_nodes: updates.updated_nodes,
638 removed_nodes: updates.removed_nodes,
639 storage_tries,
640 };
641 Ok((root, updates))
642 }
643
644 pub fn storage_trie_updates(&mut self) -> B256Map<StorageTrieUpdates> {
648 self.storage
649 .tries
650 .iter_mut()
651 .map(|(address, trie)| {
652 let trie = trie.as_revealed_mut().unwrap();
653 let updates = trie.take_updates();
654 let updates = StorageTrieUpdates {
655 is_deleted: updates.wiped,
656 storage_nodes: updates.updated_nodes,
657 removed_nodes: updates.removed_nodes,
658 };
659 (*address, updates)
660 })
661 .filter(|(_, updates)| !updates.is_empty())
662 .collect()
663 }
664
665 pub fn take_trie_updates(&mut self) -> Option<TrieUpdates> {
669 let storage_tries = self.storage_trie_updates();
670 self.state.as_revealed_mut().map(|state| {
671 let updates = state.take_updates();
672 TrieUpdates {
673 account_nodes: updates.updated_nodes,
674 removed_nodes: updates.removed_nodes,
675 storage_tries,
676 }
677 })
678 }
679
680 pub fn update_account_leaf(
682 &mut self,
683 path: Nibbles,
684 value: Vec<u8>,
685 provider_factory: impl TrieNodeProviderFactory,
686 ) -> SparseStateTrieResult<()> {
687 if !self.revealed_account_paths.contains(&path) {
688 self.revealed_account_paths.insert(path);
689 }
690
691 let provider = provider_factory.account_node_provider();
692 self.state.update_leaf(path, value, provider)?;
693 Ok(())
694 }
695
696 pub fn update_storage_leaf(
698 &mut self,
699 address: B256,
700 slot: Nibbles,
701 value: Vec<u8>,
702 provider_factory: impl TrieNodeProviderFactory,
703 ) -> SparseStateTrieResult<()> {
704 let provider = provider_factory.storage_node_provider(address);
705 self.storage
706 .tries
707 .get_mut(&address)
708 .ok_or(SparseTrieErrorKind::Blind)?
709 .update_leaf(slot, value, provider)?;
710 self.storage.get_revealed_paths_mut(address).insert(slot);
711 Ok(())
712 }
713
714 #[instrument(level = "trace", target = "trie::sparse", skip_all)]
720 pub fn update_account(
721 &mut self,
722 address: B256,
723 account: Account,
724 provider_factory: impl TrieNodeProviderFactory,
725 ) -> SparseStateTrieResult<bool> {
726 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
727 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
728 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
729 } else if self.is_account_revealed(address) {
730 trace!(target: "trie::sparse", ?address, "Retrieving storage root from account leaf to update account");
731 if let Some(value) = self.get_account_value(&address) {
733 TrieAccount::decode(&mut &value[..])?.storage_root
735 } else {
736 EMPTY_ROOT_HASH
738 }
739 } else {
740 return Err(SparseTrieErrorKind::Blind.into())
741 };
742
743 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
744 return Ok(false);
745 }
746
747 trace!(target: "trie::sparse", ?address, "Updating account");
748 let nibbles = Nibbles::unpack(address);
749 self.account_rlp_buf.clear();
750 account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
751 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
752
753 Ok(true)
754 }
755
756 #[instrument(target = "trie::sparse", skip_all)]
763 pub fn update_account_storage_root(
764 &mut self,
765 address: B256,
766 provider_factory: impl TrieNodeProviderFactory,
767 ) -> SparseStateTrieResult<bool> {
768 if !self.is_account_revealed(address) {
769 return Err(SparseTrieErrorKind::Blind.into())
770 }
771
772 let Some(mut trie_account) = self
774 .get_account_value(&address)
775 .map(|v| TrieAccount::decode(&mut &v[..]))
776 .transpose()?
777 else {
778 trace!(target: "trie::sparse", ?address, "Account not found in trie, skipping storage root update");
779 return Ok(true)
780 };
781
782 let storage_root = if let Some(storage_trie) = self.storage.tries.get_mut(&address) {
785 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
786 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
787 } else {
788 EMPTY_ROOT_HASH
789 };
790
791 trie_account.storage_root = storage_root;
793
794 if trie_account == TrieAccount::default() {
796 return Ok(false)
797 }
798
799 trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
801 let nibbles = Nibbles::unpack(address);
802 self.account_rlp_buf.clear();
803 trie_account.encode(&mut self.account_rlp_buf);
804 self.update_account_leaf(nibbles, self.account_rlp_buf.clone(), provider_factory)?;
805
806 Ok(true)
807 }
808
809 #[instrument(target = "trie::sparse", skip_all)]
811 pub fn remove_account_leaf(
812 &mut self,
813 path: &Nibbles,
814 provider_factory: impl TrieNodeProviderFactory,
815 ) -> SparseStateTrieResult<()> {
816 let provider = provider_factory.account_node_provider();
817 self.state.remove_leaf(path, provider)?;
818 Ok(())
819 }
820
821 pub fn remove_storage_leaf(
823 &mut self,
824 address: B256,
825 slot: &Nibbles,
826 provider_factory: impl TrieNodeProviderFactory,
827 ) -> SparseStateTrieResult<()> {
828 let storage_trie =
829 self.storage.tries.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
830
831 let provider = provider_factory.storage_node_provider(address);
832 storage_trie.remove_leaf(slot, provider)?;
833 Ok(())
834 }
835}
836
837#[derive(Debug, Default)]
841struct StorageTries<S = SerialSparseTrie> {
842 tries: B256Map<SparseTrie<S>>,
844 cleared_tries: Vec<SparseTrie<S>>,
846 revealed_paths: B256Map<HashSet<Nibbles>>,
848 cleared_revealed_paths: Vec<HashSet<Nibbles>>,
850 default_trie: SparseTrie<S>,
852}
853
854impl<S: SparseTrieInterface> StorageTries<S> {
855 fn clear(&mut self) {
858 self.cleared_tries.extend(self.tries.drain().map(|(_, trie)| trie.clear()));
859 self.cleared_revealed_paths.extend(self.revealed_paths.drain().map(|(_, mut set)| {
860 set.clear();
861 set
862 }));
863 }
864
865 fn shrink_to(&mut self, node_size: usize, value_size: usize) {
868 let active_count = self.tries.len();
870 let cleared_count = self.cleared_tries.len();
871 let total_tries = 1 + active_count + cleared_count;
872
873 let node_size_per_trie = node_size / total_tries;
875 let value_size_per_trie = value_size / total_tries;
876
877 for trie in self.tries.values_mut() {
879 trie.shrink_nodes_to(node_size_per_trie);
880 trie.shrink_values_to(value_size_per_trie);
881 }
882
883 for trie in &mut self.cleared_tries {
885 trie.shrink_nodes_to(node_size_per_trie);
886 trie.shrink_values_to(value_size_per_trie);
887 }
888 }
889}
890
891impl<S: SparseTrieInterface + Clone> StorageTries<S> {
892 fn get_revealed_paths_mut(&mut self, account: B256) -> &mut HashSet<Nibbles> {
895 self.revealed_paths
896 .entry(account)
897 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default())
898 }
899
900 fn get_trie_and_revealed_paths_mut(
903 &mut self,
904 account: B256,
905 ) -> (&mut SparseTrie<S>, &mut HashSet<Nibbles>) {
906 let trie = self.tries.entry(account).or_insert_with(|| {
907 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
908 });
909
910 let revealed_paths = self
911 .revealed_paths
912 .entry(account)
913 .or_insert_with(|| self.cleared_revealed_paths.pop().unwrap_or_default());
914
915 (trie, revealed_paths)
916 }
917
918 #[cfg(feature = "std")]
921 fn take_or_create_trie(&mut self, account: &B256) -> SparseTrie<S> {
922 self.tries.remove(account).unwrap_or_else(|| {
923 self.cleared_tries.pop().unwrap_or_else(|| self.default_trie.clone())
924 })
925 }
926
927 #[cfg(feature = "std")]
930 fn take_or_create_revealed_paths(&mut self, account: &B256) -> HashSet<Nibbles> {
931 self.revealed_paths
932 .remove(account)
933 .unwrap_or_else(|| self.cleared_revealed_paths.pop().unwrap_or_default())
934 }
935}
936
937#[derive(Debug, PartialEq, Eq, Default)]
938struct ProofNodesMetricValues {
939 total_nodes: usize,
941 skipped_nodes: usize,
943}
944
945#[derive(Debug, PartialEq, Eq)]
947struct FilterMappedProofNodes {
948 root_node: Option<ProofTrieNode>,
950 nodes: Vec<ProofTrieNode>,
952 new_nodes: usize,
955 metric_values: ProofNodesMetricValues,
957}
958
959fn filter_map_revealed_nodes(
963 proof_nodes: DecodedProofNodes,
964 revealed_nodes: &mut HashSet<Nibbles>,
965 branch_node_hash_masks: &HashMap<Nibbles, TrieMask>,
966 branch_node_tree_masks: &HashMap<Nibbles, TrieMask>,
967) -> SparseStateTrieResult<FilterMappedProofNodes> {
968 let mut result = FilterMappedProofNodes {
969 root_node: None,
970 nodes: Vec::with_capacity(proof_nodes.len()),
971 new_nodes: 0,
972 metric_values: Default::default(),
973 };
974
975 let proof_nodes_len = proof_nodes.len();
976 for (path, proof_node) in proof_nodes.into_inner() {
977 result.metric_values.total_nodes += 1;
978
979 let is_root = path.is_empty();
980
981 if !is_root && !revealed_nodes.insert(path) {
984 result.metric_values.skipped_nodes += 1;
985 continue
986 }
987
988 result.new_nodes += 1;
989
990 let masks = match &proof_node {
993 TrieNode::Branch(branch) => {
994 result.new_nodes += branch.state_mask.count_ones() as usize;
997 TrieMasks {
998 hash_mask: branch_node_hash_masks.get(&path).copied(),
999 tree_mask: branch_node_tree_masks.get(&path).copied(),
1000 }
1001 }
1002 TrieNode::Extension(_) => {
1003 result.new_nodes += 1;
1005 TrieMasks::none()
1006 }
1007 _ => TrieMasks::none(),
1008 };
1009
1010 let node = ProofTrieNode { path, node: proof_node, masks };
1011
1012 if is_root {
1013 if matches!(node.node, TrieNode::EmptyRoot) && proof_nodes_len > 1 {
1015 return Err(SparseStateTrieErrorKind::InvalidRootNode {
1016 path,
1017 node: alloy_rlp::encode(&node.node).into(),
1018 }
1019 .into())
1020 }
1021
1022 result.root_node = Some(node);
1023
1024 continue
1025 }
1026
1027 result.nodes.push(node);
1028 }
1029
1030 Ok(result)
1031}
1032
1033#[cfg(test)]
1034mod tests {
1035 use super::*;
1036 use crate::provider::DefaultTrieNodeProviderFactory;
1037 use alloy_primitives::{
1038 b256,
1039 map::{HashMap, HashSet},
1040 U256,
1041 };
1042 use arbitrary::Arbitrary;
1043 use rand::{rngs::StdRng, Rng, SeedableRng};
1044 use reth_primitives_traits::Account;
1045 use reth_trie::{updates::StorageTrieUpdates, HashBuilder, MultiProof, EMPTY_ROOT_HASH};
1046 use reth_trie_common::{
1047 proof::{ProofNodes, ProofRetainer},
1048 BranchNode, LeafNode, StorageMultiProof, TrieMask,
1049 };
1050
1051 #[test]
1052 fn reveal_account_path_twice() {
1053 let provider_factory = DefaultTrieNodeProviderFactory;
1054 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
1055
1056 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1057 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1058 Nibbles::default(),
1059 leaf_value.clone(),
1060 )));
1061 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1062 Nibbles::default(),
1063 leaf_value.clone(),
1064 )));
1065
1066 let multiproof = MultiProof {
1067 account_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 ..Default::default()
1080 };
1081
1082 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1084 assert!(sparse
1085 .state_trie_ref()
1086 .unwrap()
1087 .nodes_ref()
1088 .contains_key(&Nibbles::from_nibbles([0x0])),);
1089 assert_eq!(
1090 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
1091 Some(&leaf_value)
1092 );
1093
1094 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0]), &provider_factory).unwrap();
1097 assert!(!sparse
1098 .state_trie_ref()
1099 .unwrap()
1100 .nodes_ref()
1101 .contains_key(&Nibbles::from_nibbles([0x0])),);
1102 assert!(sparse
1103 .state_trie_ref()
1104 .unwrap()
1105 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1106 .is_none());
1107
1108 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1111 assert!(!sparse
1112 .state_trie_ref()
1113 .unwrap()
1114 .nodes_ref()
1115 .contains_key(&Nibbles::from_nibbles([0x0])));
1116 assert!(sparse
1117 .state_trie_ref()
1118 .unwrap()
1119 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1120 .is_none());
1121 }
1122
1123 #[test]
1124 fn reveal_storage_path_twice() {
1125 let provider_factory = DefaultTrieNodeProviderFactory;
1126 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default();
1127
1128 let leaf_value = alloy_rlp::encode(TrieAccount::default());
1129 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1130 Nibbles::default(),
1131 leaf_value.clone(),
1132 )));
1133 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
1134 Nibbles::default(),
1135 leaf_value.clone(),
1136 )));
1137
1138 let multiproof = MultiProof {
1139 storages: HashMap::from_iter([(
1140 B256::ZERO,
1141 StorageMultiProof {
1142 root: B256::ZERO,
1143 subtree: ProofNodes::from_iter([
1144 (
1145 Nibbles::default(),
1146 alloy_rlp::encode(TrieNode::Branch(BranchNode {
1147 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
1148 state_mask: TrieMask::new(0b11),
1149 }))
1150 .into(),
1151 ),
1152 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
1153 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
1154 ]),
1155 branch_node_hash_masks: Default::default(),
1156 branch_node_tree_masks: Default::default(),
1157 },
1158 )]),
1159 ..Default::default()
1160 };
1161
1162 sparse.reveal_decoded_multiproof(multiproof.clone().try_into().unwrap()).unwrap();
1164 assert!(sparse
1165 .storage_trie_ref(&B256::ZERO)
1166 .unwrap()
1167 .nodes_ref()
1168 .contains_key(&Nibbles::from_nibbles([0x0])),);
1169 assert_eq!(
1170 sparse
1171 .storage_trie_ref(&B256::ZERO)
1172 .unwrap()
1173 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
1174 Some(&leaf_value)
1175 );
1176
1177 sparse
1180 .remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0]), &provider_factory)
1181 .unwrap();
1182 assert!(!sparse
1183 .storage_trie_ref(&B256::ZERO)
1184 .unwrap()
1185 .nodes_ref()
1186 .contains_key(&Nibbles::from_nibbles([0x0])),);
1187 assert!(sparse
1188 .storage_trie_ref(&B256::ZERO)
1189 .unwrap()
1190 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1191 .is_none());
1192
1193 sparse.reveal_decoded_multiproof(multiproof.try_into().unwrap()).unwrap();
1196 assert!(!sparse
1197 .storage_trie_ref(&B256::ZERO)
1198 .unwrap()
1199 .nodes_ref()
1200 .contains_key(&Nibbles::from_nibbles([0x0])));
1201 assert!(sparse
1202 .storage_trie_ref(&B256::ZERO)
1203 .unwrap()
1204 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
1205 .is_none());
1206 }
1207
1208 #[test]
1209 fn take_trie_updates() {
1210 reth_tracing::init_test_tracing();
1211
1212 let mut rng = StdRng::seed_from_u64(1);
1214
1215 let mut bytes = [0u8; 1024];
1216 rng.fill(bytes.as_mut_slice());
1217
1218 let slot_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1219 let slot_path_1 = Nibbles::unpack(slot_1);
1220 let value_1 = U256::from(rng.random::<u64>());
1221 let slot_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1222 let slot_path_2 = Nibbles::unpack(slot_2);
1223 let value_2 = U256::from(rng.random::<u64>());
1224 let slot_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1225 let slot_path_3 = Nibbles::unpack(slot_3);
1226 let value_3 = U256::from(rng.random::<u64>());
1227
1228 let mut storage_hash_builder = HashBuilder::default()
1229 .with_proof_retainer(ProofRetainer::from_iter([slot_path_1, slot_path_2]));
1230 storage_hash_builder.add_leaf(slot_path_1, &alloy_rlp::encode_fixed_size(&value_1));
1231 storage_hash_builder.add_leaf(slot_path_2, &alloy_rlp::encode_fixed_size(&value_2));
1232
1233 let storage_root = storage_hash_builder.root();
1234 let storage_proof_nodes = storage_hash_builder.take_proof_nodes();
1235 let storage_branch_node_hash_masks = HashMap::from_iter([
1236 (Nibbles::default(), TrieMask::new(0b010)),
1237 (Nibbles::from_nibbles([0x1]), TrieMask::new(0b11)),
1238 ]);
1239
1240 let address_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
1241 let address_path_1 = Nibbles::unpack(address_1);
1242 let account_1 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1243 let mut trie_account_1 = account_1.into_trie_account(storage_root);
1244 let address_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
1245 let address_path_2 = Nibbles::unpack(address_2);
1246 let account_2 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
1247 let mut trie_account_2 = account_2.into_trie_account(EMPTY_ROOT_HASH);
1248
1249 let mut hash_builder = HashBuilder::default()
1250 .with_proof_retainer(ProofRetainer::from_iter([address_path_1, address_path_2]));
1251 hash_builder.add_leaf(address_path_1, &alloy_rlp::encode(trie_account_1));
1252 hash_builder.add_leaf(address_path_2, &alloy_rlp::encode(trie_account_2));
1253
1254 let root = hash_builder.root();
1255 let proof_nodes = hash_builder.take_proof_nodes();
1256
1257 let provider_factory = DefaultTrieNodeProviderFactory;
1258 let mut sparse = SparseStateTrie::<SerialSparseTrie>::default().with_updates(true);
1259 sparse
1260 .reveal_decoded_multiproof(
1261 MultiProof {
1262 account_subtree: proof_nodes,
1263 branch_node_hash_masks: HashMap::from_iter([(
1264 Nibbles::from_nibbles([0x1]),
1265 TrieMask::new(0b00),
1266 )]),
1267 branch_node_tree_masks: HashMap::default(),
1268 storages: HashMap::from_iter([
1269 (
1270 address_1,
1271 StorageMultiProof {
1272 root,
1273 subtree: storage_proof_nodes.clone(),
1274 branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
1275 branch_node_tree_masks: HashMap::default(),
1276 },
1277 ),
1278 (
1279 address_2,
1280 StorageMultiProof {
1281 root,
1282 subtree: storage_proof_nodes,
1283 branch_node_hash_masks: storage_branch_node_hash_masks,
1284 branch_node_tree_masks: HashMap::default(),
1285 },
1286 ),
1287 ]),
1288 }
1289 .try_into()
1290 .unwrap(),
1291 )
1292 .unwrap();
1293
1294 assert_eq!(sparse.root(&provider_factory).unwrap(), root);
1295
1296 let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1297 let address_path_3 = Nibbles::unpack(address_3);
1298 let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
1299 let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
1300
1301 sparse
1302 .update_account_leaf(
1303 address_path_3,
1304 alloy_rlp::encode(trie_account_3),
1305 &provider_factory,
1306 )
1307 .unwrap();
1308
1309 sparse
1310 .update_storage_leaf(
1311 address_1,
1312 slot_path_3,
1313 alloy_rlp::encode(value_3),
1314 &provider_factory,
1315 )
1316 .unwrap();
1317 trie_account_1.storage_root = sparse.storage_root(address_1).unwrap();
1318 sparse
1319 .update_account_leaf(
1320 address_path_1,
1321 alloy_rlp::encode(trie_account_1),
1322 &provider_factory,
1323 )
1324 .unwrap();
1325
1326 sparse.wipe_storage(address_2).unwrap();
1327 trie_account_2.storage_root = sparse.storage_root(address_2).unwrap();
1328 sparse
1329 .update_account_leaf(
1330 address_path_2,
1331 alloy_rlp::encode(trie_account_2),
1332 &provider_factory,
1333 )
1334 .unwrap();
1335
1336 sparse.root(&provider_factory).unwrap();
1337
1338 let sparse_updates = sparse.take_trie_updates().unwrap();
1339 pretty_assertions::assert_eq!(
1341 sparse_updates,
1342 TrieUpdates {
1343 account_nodes: HashMap::default(),
1344 storage_tries: HashMap::from_iter([(
1345 b256!("0x1100000000000000000000000000000000000000000000000000000000000000"),
1346 StorageTrieUpdates {
1347 is_deleted: true,
1348 storage_nodes: HashMap::default(),
1349 removed_nodes: HashSet::default()
1350 }
1351 )]),
1352 removed_nodes: HashSet::default()
1353 }
1354 );
1355 }
1356
1357 #[test]
1358 fn test_filter_map_revealed_nodes() {
1359 let mut revealed_nodes = HashSet::from_iter([Nibbles::from_nibbles([0x0])]);
1360 let leaf = TrieNode::Leaf(LeafNode::new(Nibbles::default(), alloy_rlp::encode([])));
1361 let leaf_encoded = alloy_rlp::encode(&leaf);
1362 let branch = TrieNode::Branch(BranchNode::new(
1363 vec![RlpNode::from_rlp(&leaf_encoded), RlpNode::from_rlp(&leaf_encoded)],
1364 TrieMask::new(0b11),
1365 ));
1366 let proof_nodes = alloy_trie::proof::DecodedProofNodes::from_iter([
1367 (Nibbles::default(), branch.clone()),
1368 (Nibbles::from_nibbles([0x0]), leaf.clone()),
1369 (Nibbles::from_nibbles([0x1]), leaf.clone()),
1370 ]);
1371
1372 let branch_node_hash_masks = HashMap::default();
1373 let branch_node_tree_masks = HashMap::default();
1374
1375 let decoded = filter_map_revealed_nodes(
1376 proof_nodes,
1377 &mut revealed_nodes,
1378 &branch_node_hash_masks,
1379 &branch_node_tree_masks,
1380 )
1381 .unwrap();
1382
1383 assert_eq!(
1384 decoded,
1385 FilterMappedProofNodes {
1386 root_node: Some(ProofTrieNode {
1387 path: Nibbles::default(),
1388 node: branch,
1389 masks: TrieMasks::none(),
1390 }),
1391 nodes: vec![ProofTrieNode {
1392 path: Nibbles::from_nibbles([0x1]),
1393 node: leaf,
1394 masks: TrieMasks::none(),
1395 }],
1396 new_nodes: 4,
1398 metric_values: ProofNodesMetricValues {
1400 total_nodes: 3,
1402 skipped_nodes: 1,
1404 },
1405 }
1406 );
1407 }
1408}