1use crate::{
2 blinded::{BlindedProvider, BlindedProviderFactory, DefaultBlindedProviderFactory},
3 metrics::SparseStateTrieMetrics,
4 RevealedSparseTrie, SparseTrie, TrieMasks,
5};
6use alloy_primitives::{
7 hex,
8 map::{B256Map, HashSet},
9 Bytes, B256,
10};
11use alloy_rlp::{Decodable, Encodable};
12use reth_execution_errors::{SparseStateTrieErrorKind, SparseStateTrieResult, SparseTrieErrorKind};
13use reth_primitives_traits::Account;
14use reth_tracing::tracing::trace;
15use reth_trie_common::{
16 updates::{StorageTrieUpdates, TrieUpdates},
17 MultiProof, Nibbles, RlpNode, TrieAccount, TrieNode, EMPTY_ROOT_HASH,
18 TRIE_ACCOUNT_RLP_MAX_SIZE,
19};
20use std::{collections::VecDeque, fmt, iter::Peekable};
21
22pub struct SparseStateTrie<F: BlindedProviderFactory = DefaultBlindedProviderFactory> {
24 provider_factory: F,
26 state: SparseTrie<F::AccountNodeProvider>,
28 storages: B256Map<SparseTrie<F::StorageNodeProvider>>,
30 revealed_account_paths: HashSet<Nibbles>,
32 revealed_storage_paths: B256Map<HashSet<Nibbles>>,
34 retain_updates: bool,
36 account_rlp_buf: Vec<u8>,
38 metrics: SparseStateTrieMetrics,
40}
41
42impl Default for SparseStateTrie {
43 fn default() -> Self {
44 Self {
45 provider_factory: Default::default(),
46 state: Default::default(),
47 storages: Default::default(),
48 revealed_account_paths: Default::default(),
49 revealed_storage_paths: Default::default(),
50 retain_updates: false,
51 account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
52 metrics: Default::default(),
53 }
54 }
55}
56
57impl<P: BlindedProviderFactory> fmt::Debug for SparseStateTrie<P> {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 f.debug_struct("SparseStateTrie")
60 .field("state", &self.state)
61 .field("storages", &self.storages)
62 .field("revealed_account_paths", &self.revealed_account_paths)
63 .field("revealed_storage_paths", &self.revealed_storage_paths)
64 .field("retain_updates", &self.retain_updates)
65 .field("account_rlp_buf", &hex::encode(&self.account_rlp_buf))
66 .finish_non_exhaustive()
67 }
68}
69
70impl SparseStateTrie {
71 pub fn from_state(state: SparseTrie) -> Self {
73 Self { state, ..Default::default() }
74 }
75}
76
77impl<F: BlindedProviderFactory> SparseStateTrie<F> {
78 pub fn new(provider_factory: F) -> Self {
80 Self {
81 provider_factory,
82 state: Default::default(),
83 storages: Default::default(),
84 revealed_account_paths: Default::default(),
85 revealed_storage_paths: Default::default(),
86 retain_updates: false,
87 account_rlp_buf: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
88 metrics: Default::default(),
89 }
90 }
91
92 pub const fn with_updates(mut self, retain_updates: bool) -> Self {
94 self.retain_updates = retain_updates;
95 self
96 }
97
98 pub fn is_account_revealed(&self, account: B256) -> bool {
100 self.revealed_account_paths.contains(&Nibbles::unpack(account))
101 }
102
103 pub fn is_storage_slot_revealed(&self, account: B256, slot: B256) -> bool {
105 self.revealed_storage_paths
106 .get(&account)
107 .is_some_and(|slots| slots.contains(&Nibbles::unpack(slot)))
108 }
109
110 pub fn get_account_value(&self, account: &B256) -> Option<&Vec<u8>> {
112 self.state.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(account))
113 }
114
115 pub fn get_storage_slot_value(&self, account: &B256, slot: &B256) -> Option<&Vec<u8>> {
117 self.storages.get(account)?.as_revealed_ref()?.get_leaf_value(&Nibbles::unpack(slot))
118 }
119
120 pub const fn state_trie_ref(&self) -> Option<&RevealedSparseTrie<F::AccountNodeProvider>> {
122 self.state.as_revealed_ref()
123 }
124
125 pub fn storage_trie_ref(
127 &self,
128 address: &B256,
129 ) -> Option<&RevealedSparseTrie<F::StorageNodeProvider>> {
130 self.storages.get(address).and_then(|e| e.as_revealed_ref())
131 }
132
133 pub fn storage_trie_mut(
135 &mut self,
136 address: &B256,
137 ) -> Option<&mut RevealedSparseTrie<F::StorageNodeProvider>> {
138 self.storages.get_mut(address).and_then(|e| e.as_revealed_mut())
139 }
140
141 pub fn take_storage_trie(
143 &mut self,
144 address: &B256,
145 ) -> Option<SparseTrie<F::StorageNodeProvider>> {
146 self.storages.remove(address)
147 }
148
149 pub fn insert_storage_trie(
151 &mut self,
152 address: B256,
153 storage_trie: SparseTrie<F::StorageNodeProvider>,
154 ) {
155 self.storages.insert(address, storage_trie);
156 }
157
158 pub fn reveal_account(
164 &mut self,
165 account: B256,
166 proof: impl IntoIterator<Item = (Nibbles, Bytes)>,
167 ) -> SparseStateTrieResult<()> {
168 assert!(!self.retain_updates);
169
170 if self.is_account_revealed(account) {
171 return Ok(());
172 }
173
174 let mut proof = proof.into_iter().peekable();
175
176 let Some(root_node) = self.validate_root_node(&mut proof)? else { return Ok(()) };
177
178 let trie = self.state.reveal_root_with_provider(
180 self.provider_factory.account_node_provider(),
181 root_node,
182 TrieMasks::none(),
183 self.retain_updates,
184 )?;
185
186 for (path, bytes) in proof {
188 if self.revealed_account_paths.contains(&path) {
189 continue
190 }
191 let node = TrieNode::decode(&mut &bytes[..])?;
192 trie.reveal_node(path.clone(), node, TrieMasks::none())?;
193
194 self.revealed_account_paths.insert(path);
196 }
197
198 Ok(())
199 }
200
201 pub fn reveal_storage_slot(
207 &mut self,
208 account: B256,
209 slot: B256,
210 proof: impl IntoIterator<Item = (Nibbles, Bytes)>,
211 ) -> SparseStateTrieResult<()> {
212 assert!(!self.retain_updates);
213
214 if self.is_storage_slot_revealed(account, slot) {
215 return Ok(());
216 }
217
218 let mut proof = proof.into_iter().peekable();
219
220 let Some(root_node) = self.validate_root_node(&mut proof)? else { return Ok(()) };
221
222 let trie = self.storages.entry(account).or_default().reveal_root_with_provider(
224 self.provider_factory.storage_node_provider(account),
225 root_node,
226 TrieMasks::none(),
227 self.retain_updates,
228 )?;
229
230 let revealed_nodes = self.revealed_storage_paths.entry(account).or_default();
231
232 for (path, bytes) in proof {
234 if revealed_nodes.contains(&path) {
236 continue
237 }
238 let node = TrieNode::decode(&mut &bytes[..])?;
239 trie.reveal_node(path.clone(), node, TrieMasks::none())?;
240
241 revealed_nodes.insert(path);
243 }
244
245 Ok(())
246 }
247
248 pub fn reveal_multiproof(&mut self, multiproof: MultiProof) -> SparseStateTrieResult<()> {
251 let account_subtree = multiproof.account_subtree.into_nodes_sorted();
252 let mut account_nodes = account_subtree.into_iter().peekable();
253
254 if let Some(root_node) = self.validate_root_node(&mut account_nodes)? {
255 let trie = self.state.reveal_root_with_provider(
257 self.provider_factory.account_node_provider(),
258 root_node,
259 TrieMasks {
260 hash_mask: multiproof.branch_node_hash_masks.get(&Nibbles::default()).copied(),
261 tree_mask: multiproof.branch_node_tree_masks.get(&Nibbles::default()).copied(),
262 },
263 self.retain_updates,
264 )?;
265
266 for (path, bytes) in account_nodes {
268 self.metrics.increment_total_account_nodes();
269 if self.revealed_account_paths.contains(&path) {
271 self.metrics.increment_skipped_account_nodes();
272 continue
273 }
274 let node = TrieNode::decode(&mut &bytes[..])?;
275 let (hash_mask, tree_mask) = if let TrieNode::Branch(_) = node {
276 (
277 multiproof.branch_node_hash_masks.get(&path).copied(),
278 multiproof.branch_node_tree_masks.get(&path).copied(),
279 )
280 } else {
281 (None, None)
282 };
283
284 trace!(target: "trie::sparse", ?path, ?node, ?hash_mask, ?tree_mask, "Revealing account node");
285 trie.reveal_node(path.clone(), node, TrieMasks { hash_mask, tree_mask })?;
286
287 self.revealed_account_paths.insert(path);
289 }
290 }
291
292 for (account, storage_subtree) in multiproof.storages {
293 let subtree = storage_subtree.subtree.into_nodes_sorted();
294 let mut nodes = subtree.into_iter().peekable();
295
296 if let Some(root_node) = self.validate_root_node(&mut nodes)? {
297 let trie = self.storages.entry(account).or_default().reveal_root_with_provider(
299 self.provider_factory.storage_node_provider(account),
300 root_node,
301 TrieMasks {
302 hash_mask: storage_subtree
303 .branch_node_hash_masks
304 .get(&Nibbles::default())
305 .copied(),
306 tree_mask: storage_subtree
307 .branch_node_tree_masks
308 .get(&Nibbles::default())
309 .copied(),
310 },
311 self.retain_updates,
312 )?;
313 let revealed_nodes = self.revealed_storage_paths.entry(account).or_default();
314
315 for (path, bytes) in nodes {
317 self.metrics.increment_total_storage_nodes();
318 if revealed_nodes.contains(&path) {
320 self.metrics.increment_skipped_storage_nodes();
321 continue
322 }
323 let node = TrieNode::decode(&mut &bytes[..])?;
324 let (hash_mask, tree_mask) = if let TrieNode::Branch(_) = node {
325 (
326 storage_subtree.branch_node_hash_masks.get(&path).copied(),
327 storage_subtree.branch_node_tree_masks.get(&path).copied(),
328 )
329 } else {
330 (None, None)
331 };
332
333 trace!(target: "trie::sparse", ?account, ?path, ?node, ?hash_mask, ?tree_mask, "Revealing storage node");
334 trie.reveal_node(path.clone(), node, TrieMasks { hash_mask, tree_mask })?;
335
336 revealed_nodes.insert(path);
338 }
339 }
340 }
341
342 Ok(())
343 }
344
345 pub fn reveal_witness(
349 &mut self,
350 state_root: B256,
351 witness: &B256Map<Bytes>,
352 ) -> SparseStateTrieResult<()> {
353 let mut queue = VecDeque::from([(state_root, Nibbles::default(), None)]);
356
357 while let Some((hash, path, maybe_account)) = queue.pop_front() {
358 let Some(trie_node_bytes) = witness.get(&hash) else { continue };
360 let trie_node = TrieNode::decode(&mut &trie_node_bytes[..])?;
361
362 match &trie_node {
364 TrieNode::Branch(branch) => {
365 for (idx, maybe_child) in branch.as_ref().children() {
366 if let Some(child_hash) = maybe_child.and_then(RlpNode::as_hash) {
367 let mut child_path = path.clone();
368 child_path.push_unchecked(idx);
369 queue.push_back((child_hash, child_path, maybe_account));
370 }
371 }
372 }
373 TrieNode::Extension(ext) => {
374 if let Some(child_hash) = ext.child.as_hash() {
375 let mut child_path = path.clone();
376 child_path.extend_from_slice_unchecked(&ext.key);
377 queue.push_back((child_hash, child_path, maybe_account));
378 }
379 }
380 TrieNode::Leaf(leaf) => {
381 let mut full_path = path.clone();
382 full_path.extend_from_slice_unchecked(&leaf.key);
383 if maybe_account.is_none() {
384 let hashed_address = B256::from_slice(&full_path.pack());
385 let account = TrieAccount::decode(&mut &leaf.value[..])?;
386 if account.storage_root != EMPTY_ROOT_HASH {
387 queue.push_back((
388 account.storage_root,
389 Nibbles::default(),
390 Some(hashed_address),
391 ));
392 }
393 }
394 }
395 TrieNode::EmptyRoot => {} };
397
398 if let Some(account) = maybe_account {
400 if self
402 .revealed_storage_paths
403 .get(&account)
404 .is_none_or(|paths| !paths.contains(&path))
405 {
406 let storage_trie_entry = self.storages.entry(account).or_default();
407 if path.is_empty() {
408 storage_trie_entry.reveal_root_with_provider(
410 self.provider_factory.storage_node_provider(account),
411 trie_node,
412 TrieMasks::none(),
413 self.retain_updates,
414 )?;
415 } else {
416 storage_trie_entry
418 .as_revealed_mut()
419 .ok_or(SparseTrieErrorKind::Blind)?
420 .reveal_node(path.clone(), trie_node, TrieMasks::none())?;
421 }
422
423 self.revealed_storage_paths.entry(account).or_default().insert(path);
425 }
426 }
427 else if !self.revealed_account_paths.contains(&path) {
429 if path.is_empty() {
430 self.state.reveal_root_with_provider(
432 self.provider_factory.account_node_provider(),
433 trie_node,
434 TrieMasks::none(),
435 self.retain_updates,
436 )?;
437 } else {
438 self.state.as_revealed_mut().ok_or(SparseTrieErrorKind::Blind)?.reveal_node(
440 path.clone(),
441 trie_node,
442 TrieMasks::none(),
443 )?;
444 }
445
446 self.revealed_account_paths.insert(path);
448 }
449 }
450
451 Ok(())
452 }
453
454 fn validate_root_node<I: Iterator<Item = (Nibbles, Bytes)>>(
456 &self,
457 proof: &mut Peekable<I>,
458 ) -> SparseStateTrieResult<Option<TrieNode>> {
459 let mut proof = proof.into_iter().peekable();
460
461 let Some((path, node)) = proof.next() else { return Ok(None) };
463 if !path.is_empty() {
464 return Err(SparseStateTrieErrorKind::InvalidRootNode { path, node }.into())
465 }
466
467 let root_node = TrieNode::decode(&mut &node[..])?;
469 if matches!(root_node, TrieNode::EmptyRoot) && proof.peek().is_some() {
470 return Err(SparseStateTrieErrorKind::InvalidRootNode { path, node }.into())
471 }
472
473 Ok(Some(root_node))
474 }
475
476 pub fn wipe_storage(&mut self, address: B256) -> SparseStateTrieResult<()> {
478 if let Some(trie) = self.storages.get_mut(&address) {
479 trie.wipe()?;
480 }
481 Ok(())
482 }
483
484 pub fn calculate_below_level(&mut self, level: usize) {
488 if let SparseTrie::Revealed(trie) = &mut self.state {
489 trie.update_rlp_node_level(level);
490 }
491 }
492
493 pub fn storage_root(&mut self, account: B256) -> Option<B256> {
495 self.storages.get_mut(&account).and_then(|trie| trie.root())
496 }
497
498 fn revealed_trie_mut(
502 &mut self,
503 ) -> SparseStateTrieResult<&mut RevealedSparseTrie<F::AccountNodeProvider>> {
504 match self.state {
505 SparseTrie::Blind => {
506 let (root_node, hash_mask, tree_mask) = self
507 .provider_factory
508 .account_node_provider()
509 .blinded_node(&Nibbles::default())?
510 .map(|node| {
511 TrieNode::decode(&mut &node.node[..])
512 .map(|decoded| (decoded, node.hash_mask, node.tree_mask))
513 })
514 .transpose()?
515 .unwrap_or((TrieNode::EmptyRoot, None, None));
516 self.state
517 .reveal_root_with_provider(
518 self.provider_factory.account_node_provider(),
519 root_node,
520 TrieMasks { hash_mask, tree_mask },
521 self.retain_updates,
522 )
523 .map_err(Into::into)
524 }
525 SparseTrie::Revealed(ref mut trie) => Ok(trie),
526 }
527 }
528
529 pub fn root(&mut self) -> SparseStateTrieResult<B256> {
533 self.metrics.record();
535
536 Ok(self.revealed_trie_mut()?.root())
537 }
538
539 pub fn root_with_updates(&mut self) -> SparseStateTrieResult<(B256, TrieUpdates)> {
541 self.metrics.record();
543
544 let storage_tries = self.storage_trie_updates();
545 let revealed = self.revealed_trie_mut()?;
546
547 let (root, updates) = (revealed.root(), revealed.take_updates());
548 let updates = TrieUpdates {
549 account_nodes: updates.updated_nodes,
550 removed_nodes: updates.removed_nodes,
551 storage_tries,
552 };
553 Ok((root, updates))
554 }
555
556 pub fn storage_trie_updates(&mut self) -> B256Map<StorageTrieUpdates> {
560 self.storages
561 .iter_mut()
562 .map(|(address, trie)| {
563 let trie = trie.as_revealed_mut().unwrap();
564 let updates = trie.take_updates();
565 let updates = StorageTrieUpdates {
566 is_deleted: updates.wiped,
567 storage_nodes: updates.updated_nodes,
568 removed_nodes: updates.removed_nodes,
569 };
570 (*address, updates)
571 })
572 .filter(|(_, updates)| !updates.is_empty())
573 .collect()
574 }
575
576 pub fn take_trie_updates(&mut self) -> Option<TrieUpdates> {
580 let storage_tries = self.storage_trie_updates();
581 self.state.as_revealed_mut().map(|state| {
582 let updates = state.take_updates();
583 TrieUpdates {
584 account_nodes: updates.updated_nodes,
585 removed_nodes: updates.removed_nodes,
586 storage_tries,
587 }
588 })
589 }
590}
591impl<F: BlindedProviderFactory> SparseStateTrie<F> {
592 pub fn update_account_leaf(
594 &mut self,
595 path: Nibbles,
596 value: Vec<u8>,
597 ) -> SparseStateTrieResult<()> {
598 if !self.revealed_account_paths.contains(&path) {
599 self.revealed_account_paths.insert(path.clone());
600 }
601
602 self.state.update_leaf(path, value)?;
603 Ok(())
604 }
605
606 pub fn update_storage_leaf(
608 &mut self,
609 address: B256,
610 slot: Nibbles,
611 value: Vec<u8>,
612 ) -> SparseStateTrieResult<()> {
613 if !self.revealed_storage_paths.get(&address).is_some_and(|slots| slots.contains(&slot)) {
614 self.revealed_storage_paths.entry(address).or_default().insert(slot.clone());
615 }
616
617 let storage_trie = self.storages.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
618 storage_trie.update_leaf(slot, value)?;
619 Ok(())
620 }
621
622 pub fn update_account(&mut self, address: B256, account: Account) -> SparseStateTrieResult<()> {
627 let nibbles = Nibbles::unpack(address);
628
629 let storage_root = if let Some(storage_trie) = self.storages.get_mut(&address) {
630 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
631 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
632 } else if self.is_account_revealed(address) {
633 trace!(target: "trie::sparse", ?address, "Retrieving storage root from account leaf to update account");
634 if let Some(value) = self.get_account_value(&address) {
636 TrieAccount::decode(&mut &value[..])?.storage_root
638 } else {
639 EMPTY_ROOT_HASH
641 }
642 } else {
643 return Err(SparseTrieErrorKind::Blind.into())
644 };
645
646 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
647 trace!(target: "trie::sparse", ?address, "Removing account");
648 self.remove_account_leaf(&nibbles)
649 } else {
650 trace!(target: "trie::sparse", ?address, "Updating account");
651 self.account_rlp_buf.clear();
652 account.into_trie_account(storage_root).encode(&mut self.account_rlp_buf);
653 self.update_account_leaf(nibbles, self.account_rlp_buf.clone())
654 }
655 }
656
657 pub fn update_account_storage_root(&mut self, address: B256) -> SparseStateTrieResult<()> {
664 if !self.is_account_revealed(address) {
665 return Err(SparseTrieErrorKind::Blind.into())
666 }
667
668 let Some(mut trie_account) = self
670 .get_account_value(&address)
671 .map(|v| TrieAccount::decode(&mut &v[..]))
672 .transpose()?
673 else {
674 trace!(target: "trie::sparse", ?address, "Account not found in trie, skipping storage root update");
675 return Ok(())
676 };
677
678 let storage_root = if let Some(storage_trie) = self.storages.get_mut(&address) {
681 trace!(target: "trie::sparse", ?address, "Calculating storage root to update account");
682 storage_trie.root().ok_or(SparseTrieErrorKind::Blind)?
683 } else {
684 EMPTY_ROOT_HASH
685 };
686
687 trie_account.storage_root = storage_root;
689
690 let nibbles = Nibbles::unpack(address);
691 if trie_account == TrieAccount::default() {
692 trace!(target: "trie::sparse", ?address, "Removing account because the storage root is empty");
694 self.remove_account_leaf(&nibbles)?;
695 } else {
696 trace!(target: "trie::sparse", ?address, "Updating account with the new storage root");
698 self.account_rlp_buf.clear();
699 trie_account.encode(&mut self.account_rlp_buf);
700 self.update_account_leaf(nibbles, self.account_rlp_buf.clone())?;
701 }
702
703 Ok(())
704 }
705
706 pub fn remove_account_leaf(&mut self, path: &Nibbles) -> SparseStateTrieResult<()> {
708 self.state.remove_leaf(path)?;
709 Ok(())
710 }
711
712 pub fn remove_storage_leaf(
714 &mut self,
715 address: B256,
716 slot: &Nibbles,
717 ) -> SparseStateTrieResult<()> {
718 let storage_trie = self.storages.get_mut(&address).ok_or(SparseTrieErrorKind::Blind)?;
719 storage_trie.remove_leaf(slot)?;
720 Ok(())
721 }
722}
723
724#[cfg(test)]
725mod tests {
726 use super::*;
727 use alloy_primitives::{
728 b256,
729 map::{HashMap, HashSet},
730 Bytes, U256,
731 };
732 use alloy_rlp::EMPTY_STRING_CODE;
733 use arbitrary::Arbitrary;
734 use assert_matches::assert_matches;
735 use rand::{rngs::StdRng, Rng, SeedableRng};
736 use reth_primitives_traits::Account;
737 use reth_trie::{updates::StorageTrieUpdates, HashBuilder, EMPTY_ROOT_HASH};
738 use reth_trie_common::{
739 proof::{ProofNodes, ProofRetainer},
740 BranchNode, LeafNode, StorageMultiProof, TrieMask,
741 };
742
743 #[test]
744 fn validate_root_node_first_node_not_root() {
745 let sparse = SparseStateTrie::default();
746 let proof = [(Nibbles::from_nibbles([0x1]), Bytes::from([EMPTY_STRING_CODE]))];
747 assert_matches!(
748 sparse.validate_root_node(&mut proof.into_iter().peekable()).map_err(|e| e.into_kind()),
749 Err(SparseStateTrieErrorKind::InvalidRootNode { .. })
750 );
751 }
752
753 #[test]
754 fn validate_root_node_invalid_proof_with_empty_root() {
755 let sparse = SparseStateTrie::default();
756 let proof = [
757 (Nibbles::default(), Bytes::from([EMPTY_STRING_CODE])),
758 (Nibbles::from_nibbles([0x1]), Bytes::new()),
759 ];
760 assert_matches!(
761 sparse.validate_root_node(&mut proof.into_iter().peekable()).map_err(|e| e.into_kind()),
762 Err(SparseStateTrieErrorKind::InvalidRootNode { .. })
763 );
764 }
765
766 #[test]
767 fn reveal_account_empty() {
768 let retainer = ProofRetainer::from_iter([Nibbles::default()]);
769 let mut hash_builder = HashBuilder::default().with_proof_retainer(retainer);
770 hash_builder.root();
771 let proofs = hash_builder.take_proof_nodes();
772 assert_eq!(proofs.len(), 1);
773
774 let mut sparse = SparseStateTrie::default();
775 assert_eq!(sparse.state, SparseTrie::Blind);
776
777 sparse.reveal_account(Default::default(), proofs.into_inner()).unwrap();
778 assert_eq!(sparse.state, SparseTrie::revealed_empty());
779 }
780
781 #[test]
782 fn reveal_storage_slot_empty() {
783 let retainer = ProofRetainer::from_iter([Nibbles::default()]);
784 let mut hash_builder = HashBuilder::default().with_proof_retainer(retainer);
785 hash_builder.root();
786 let proofs = hash_builder.take_proof_nodes();
787 assert_eq!(proofs.len(), 1);
788
789 let mut sparse = SparseStateTrie::default();
790 assert!(sparse.storages.is_empty());
791
792 sparse
793 .reveal_storage_slot(Default::default(), Default::default(), proofs.into_inner())
794 .unwrap();
795 assert_eq!(
796 sparse.storages,
797 HashMap::from_iter([(Default::default(), SparseTrie::revealed_empty())])
798 );
799 }
800
801 #[test]
802 fn reveal_account_path_twice() {
803 let mut sparse = SparseStateTrie::default();
804
805 let leaf_value = alloy_rlp::encode(TrieAccount::default());
806 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
807 Nibbles::default(),
808 leaf_value.clone(),
809 )));
810 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
811 Nibbles::default(),
812 leaf_value.clone(),
813 )));
814
815 let multiproof = MultiProof {
816 account_subtree: ProofNodes::from_iter([
817 (
818 Nibbles::default(),
819 alloy_rlp::encode(TrieNode::Branch(BranchNode {
820 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
821 state_mask: TrieMask::new(0b11),
822 }))
823 .into(),
824 ),
825 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
826 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
827 ]),
828 ..Default::default()
829 };
830
831 sparse.reveal_multiproof(multiproof.clone()).unwrap();
833 assert!(sparse
834 .state_trie_ref()
835 .unwrap()
836 .nodes_ref()
837 .contains_key(&Nibbles::from_nibbles([0x0])),);
838 assert_eq!(
839 sparse.state_trie_ref().unwrap().get_leaf_value(&Nibbles::from_nibbles([0x0])),
840 Some(&leaf_value)
841 );
842
843 sparse.remove_account_leaf(&Nibbles::from_nibbles([0x0])).unwrap();
846 assert!(!sparse
847 .state_trie_ref()
848 .unwrap()
849 .nodes_ref()
850 .contains_key(&Nibbles::from_nibbles([0x0])),);
851 assert!(sparse
852 .state_trie_ref()
853 .unwrap()
854 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
855 .is_none());
856
857 sparse.reveal_multiproof(multiproof).unwrap();
860 assert!(!sparse
861 .state_trie_ref()
862 .unwrap()
863 .nodes_ref()
864 .contains_key(&Nibbles::from_nibbles([0x0])));
865 assert!(sparse
866 .state_trie_ref()
867 .unwrap()
868 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
869 .is_none());
870 }
871
872 #[test]
873 fn reveal_storage_path_twice() {
874 let mut sparse = SparseStateTrie::default();
875
876 let leaf_value = alloy_rlp::encode(TrieAccount::default());
877 let leaf_1 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
878 Nibbles::default(),
879 leaf_value.clone(),
880 )));
881 let leaf_2 = alloy_rlp::encode(TrieNode::Leaf(LeafNode::new(
882 Nibbles::default(),
883 leaf_value.clone(),
884 )));
885
886 let multiproof = MultiProof {
887 storages: HashMap::from_iter([(
888 B256::ZERO,
889 StorageMultiProof {
890 root: B256::ZERO,
891 subtree: ProofNodes::from_iter([
892 (
893 Nibbles::default(),
894 alloy_rlp::encode(TrieNode::Branch(BranchNode {
895 stack: vec![RlpNode::from_rlp(&leaf_1), RlpNode::from_rlp(&leaf_2)],
896 state_mask: TrieMask::new(0b11),
897 }))
898 .into(),
899 ),
900 (Nibbles::from_nibbles([0x0]), leaf_1.clone().into()),
901 (Nibbles::from_nibbles([0x1]), leaf_1.clone().into()),
902 ]),
903 branch_node_hash_masks: Default::default(),
904 branch_node_tree_masks: Default::default(),
905 },
906 )]),
907 ..Default::default()
908 };
909
910 sparse.reveal_multiproof(multiproof.clone()).unwrap();
912 assert!(sparse
913 .storage_trie_ref(&B256::ZERO)
914 .unwrap()
915 .nodes_ref()
916 .contains_key(&Nibbles::from_nibbles([0x0])),);
917 assert_eq!(
918 sparse
919 .storage_trie_ref(&B256::ZERO)
920 .unwrap()
921 .get_leaf_value(&Nibbles::from_nibbles([0x0])),
922 Some(&leaf_value)
923 );
924
925 sparse.remove_storage_leaf(B256::ZERO, &Nibbles::from_nibbles([0x0])).unwrap();
928 assert!(!sparse
929 .storage_trie_ref(&B256::ZERO)
930 .unwrap()
931 .nodes_ref()
932 .contains_key(&Nibbles::from_nibbles([0x0])),);
933 assert!(sparse
934 .storage_trie_ref(&B256::ZERO)
935 .unwrap()
936 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
937 .is_none());
938
939 sparse.reveal_multiproof(multiproof).unwrap();
942 assert!(!sparse
943 .storage_trie_ref(&B256::ZERO)
944 .unwrap()
945 .nodes_ref()
946 .contains_key(&Nibbles::from_nibbles([0x0])));
947 assert!(sparse
948 .storage_trie_ref(&B256::ZERO)
949 .unwrap()
950 .get_leaf_value(&Nibbles::from_nibbles([0x0]))
951 .is_none());
952 }
953
954 #[test]
955 fn take_trie_updates() {
956 reth_tracing::init_test_tracing();
957
958 let mut rng = StdRng::seed_from_u64(1);
960
961 let mut bytes = [0u8; 1024];
962 rng.fill(bytes.as_mut_slice());
963
964 let slot_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
965 let slot_path_1 = Nibbles::unpack(slot_1);
966 let value_1 = U256::from(rng.gen::<u64>());
967 let slot_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
968 let slot_path_2 = Nibbles::unpack(slot_2);
969 let value_2 = U256::from(rng.gen::<u64>());
970 let slot_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
971 let slot_path_3 = Nibbles::unpack(slot_3);
972 let value_3 = U256::from(rng.gen::<u64>());
973
974 let mut storage_hash_builder =
975 HashBuilder::default().with_proof_retainer(ProofRetainer::from_iter([
976 slot_path_1.clone(),
977 slot_path_2.clone(),
978 ]));
979 storage_hash_builder.add_leaf(slot_path_1, &alloy_rlp::encode_fixed_size(&value_1));
980 storage_hash_builder.add_leaf(slot_path_2, &alloy_rlp::encode_fixed_size(&value_2));
981
982 let storage_root = storage_hash_builder.root();
983 let storage_proof_nodes = storage_hash_builder.take_proof_nodes();
984 let storage_branch_node_hash_masks = HashMap::from_iter([
985 (Nibbles::default(), TrieMask::new(0b010)),
986 (Nibbles::from_nibbles([0x1]), TrieMask::new(0b11)),
987 ]);
988
989 let address_1 = b256!("0x1000000000000000000000000000000000000000000000000000000000000000");
990 let address_path_1 = Nibbles::unpack(address_1);
991 let account_1 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
992 let mut trie_account_1 = account_1.into_trie_account(storage_root);
993 let address_2 = b256!("0x1100000000000000000000000000000000000000000000000000000000000000");
994 let address_path_2 = Nibbles::unpack(address_2);
995 let account_2 = Account::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap();
996 let mut trie_account_2 = account_2.into_trie_account(EMPTY_ROOT_HASH);
997
998 let mut hash_builder =
999 HashBuilder::default().with_proof_retainer(ProofRetainer::from_iter([
1000 address_path_1.clone(),
1001 address_path_2.clone(),
1002 ]));
1003 hash_builder.add_leaf(address_path_1.clone(), &alloy_rlp::encode(trie_account_1));
1004 hash_builder.add_leaf(address_path_2.clone(), &alloy_rlp::encode(trie_account_2));
1005
1006 let root = hash_builder.root();
1007 let proof_nodes = hash_builder.take_proof_nodes();
1008
1009 let mut sparse = SparseStateTrie::default().with_updates(true);
1010 sparse
1011 .reveal_multiproof(MultiProof {
1012 account_subtree: proof_nodes,
1013 branch_node_hash_masks: HashMap::from_iter([(
1014 Nibbles::from_nibbles([0x1]),
1015 TrieMask::new(0b00),
1016 )]),
1017 branch_node_tree_masks: HashMap::default(),
1018 storages: HashMap::from_iter([
1019 (
1020 address_1,
1021 StorageMultiProof {
1022 root,
1023 subtree: storage_proof_nodes.clone(),
1024 branch_node_hash_masks: storage_branch_node_hash_masks.clone(),
1025 branch_node_tree_masks: HashMap::default(),
1026 },
1027 ),
1028 (
1029 address_2,
1030 StorageMultiProof {
1031 root,
1032 subtree: storage_proof_nodes,
1033 branch_node_hash_masks: storage_branch_node_hash_masks,
1034 branch_node_tree_masks: HashMap::default(),
1035 },
1036 ),
1037 ]),
1038 })
1039 .unwrap();
1040
1041 assert_eq!(sparse.root().unwrap(), root);
1042
1043 let address_3 = b256!("0x2000000000000000000000000000000000000000000000000000000000000000");
1044 let address_path_3 = Nibbles::unpack(address_3);
1045 let account_3 = Account { nonce: account_1.nonce + 1, ..account_1 };
1046 let trie_account_3 = account_3.into_trie_account(EMPTY_ROOT_HASH);
1047
1048 sparse.update_account_leaf(address_path_3, alloy_rlp::encode(trie_account_3)).unwrap();
1049
1050 sparse.update_storage_leaf(address_1, slot_path_3, alloy_rlp::encode(value_3)).unwrap();
1051 trie_account_1.storage_root = sparse.storage_root(address_1).unwrap();
1052 sparse.update_account_leaf(address_path_1, alloy_rlp::encode(trie_account_1)).unwrap();
1053
1054 sparse.wipe_storage(address_2).unwrap();
1055 trie_account_2.storage_root = sparse.storage_root(address_2).unwrap();
1056 sparse.update_account_leaf(address_path_2, alloy_rlp::encode(trie_account_2)).unwrap();
1057
1058 sparse.root().unwrap();
1059
1060 let sparse_updates = sparse.take_trie_updates().unwrap();
1061 pretty_assertions::assert_eq!(
1063 sparse_updates,
1064 TrieUpdates {
1065 account_nodes: HashMap::default(),
1066 storage_tries: HashMap::from_iter([(
1067 b256!("0x1100000000000000000000000000000000000000000000000000000000000000"),
1068 StorageTrieUpdates {
1069 is_deleted: true,
1070 storage_nodes: HashMap::default(),
1071 removed_nodes: HashSet::default()
1072 }
1073 )]),
1074 removed_nodes: HashSet::default()
1075 }
1076 );
1077 }
1078}