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