reth_trie/proof/
trie_node.rs

1use super::{Proof, StorageProof};
2use crate::{hashed_cursor::HashedCursorFactory, trie_cursor::TrieCursorFactory};
3use alloy_primitives::{map::HashSet, B256};
4use reth_execution_errors::{SparseTrieError, SparseTrieErrorKind};
5use reth_trie_common::{MultiProofTargets, Nibbles};
6use reth_trie_sparse::provider::{
7    pad_path_to_key, RevealedNode, TrieNodeProvider, TrieNodeProviderFactory,
8};
9use std::time::Instant;
10use tracing::{enabled, trace, Level};
11
12/// Factory for instantiating providers capable of retrieving blinded trie nodes via proofs.
13#[derive(Debug, Clone)]
14pub struct ProofTrieNodeProviderFactory<T, H> {
15    /// The cursor factory for traversing trie nodes.
16    trie_cursor_factory: T,
17    /// The factory for hashed cursors.
18    hashed_cursor_factory: H,
19}
20
21impl<T, H> ProofTrieNodeProviderFactory<T, H> {
22    /// Create new proof-based blinded provider factory.
23    pub const fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
24        Self { trie_cursor_factory, hashed_cursor_factory }
25    }
26}
27
28impl<T, H> TrieNodeProviderFactory for ProofTrieNodeProviderFactory<T, H>
29where
30    T: TrieCursorFactory + Clone + Send + Sync,
31    H: HashedCursorFactory + Clone + Send + Sync,
32{
33    type AccountNodeProvider = ProofBlindedAccountProvider<T, H>;
34    type StorageNodeProvider = ProofBlindedStorageProvider<T, H>;
35
36    fn account_node_provider(&self) -> Self::AccountNodeProvider {
37        ProofBlindedAccountProvider {
38            trie_cursor_factory: self.trie_cursor_factory.clone(),
39            hashed_cursor_factory: self.hashed_cursor_factory.clone(),
40        }
41    }
42
43    fn storage_node_provider(&self, account: B256) -> Self::StorageNodeProvider {
44        ProofBlindedStorageProvider {
45            trie_cursor_factory: self.trie_cursor_factory.clone(),
46            hashed_cursor_factory: self.hashed_cursor_factory.clone(),
47            account,
48        }
49    }
50}
51
52/// Blinded provider for retrieving account trie nodes by path.
53#[derive(Debug)]
54pub struct ProofBlindedAccountProvider<T, H> {
55    /// The cursor factory for traversing trie nodes.
56    trie_cursor_factory: T,
57    /// The factory for hashed cursors.
58    hashed_cursor_factory: H,
59}
60
61impl<T, H> ProofBlindedAccountProvider<T, H> {
62    /// Create new proof-based blinded account node provider.
63    pub const fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
64        Self { trie_cursor_factory, hashed_cursor_factory }
65    }
66}
67
68impl<T, H> TrieNodeProvider for ProofBlindedAccountProvider<T, H>
69where
70    T: TrieCursorFactory,
71    H: HashedCursorFactory,
72{
73    fn trie_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
74        let start = enabled!(target: "trie::proof::blinded", Level::TRACE).then(Instant::now);
75
76        let targets = MultiProofTargets::from_iter([(pad_path_to_key(path), HashSet::default())]);
77        let mut proof = Proof::new(&self.trie_cursor_factory, &self.hashed_cursor_factory)
78            .with_branch_node_masks(true)
79            .multiproof(targets)
80            .map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
81        let node = proof.account_subtree.into_inner().remove(path);
82        let tree_mask = proof.branch_node_tree_masks.remove(path);
83        let hash_mask = proof.branch_node_hash_masks.remove(path);
84
85        trace!(
86            target: "trie::proof::blinded",
87            elapsed = ?start.unwrap().elapsed(),
88            ?path,
89            ?node,
90            ?tree_mask,
91            ?hash_mask,
92            "Blinded node for account trie"
93        );
94        Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
95    }
96}
97
98/// Blinded provider for retrieving storage trie nodes by path.
99#[derive(Debug)]
100pub struct ProofBlindedStorageProvider<T, H> {
101    /// The cursor factory for traversing trie nodes.
102    trie_cursor_factory: T,
103    /// The factory for hashed cursors.
104    hashed_cursor_factory: H,
105    /// Target account.
106    account: B256,
107}
108
109impl<T, H> ProofBlindedStorageProvider<T, H> {
110    /// Create new proof-based blinded storage node provider.
111    pub const fn new(trie_cursor_factory: T, hashed_cursor_factory: H, account: B256) -> Self {
112        Self { trie_cursor_factory, hashed_cursor_factory, account }
113    }
114}
115
116impl<T, H> TrieNodeProvider for ProofBlindedStorageProvider<T, H>
117where
118    T: TrieCursorFactory,
119    H: HashedCursorFactory,
120{
121    fn trie_node(&self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
122        let start = enabled!(target: "trie::proof::blinded", Level::TRACE).then(Instant::now);
123
124        let targets = HashSet::from_iter([pad_path_to_key(path)]);
125        let mut proof = StorageProof::new_hashed(
126            &self.trie_cursor_factory,
127            &self.hashed_cursor_factory,
128            self.account,
129        )
130        .with_branch_node_masks(true)
131        .storage_multiproof(targets)
132        .map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
133        let node = proof.subtree.into_inner().remove(path);
134        let tree_mask = proof.branch_node_tree_masks.remove(path);
135        let hash_mask = proof.branch_node_hash_masks.remove(path);
136
137        trace!(
138            target: "trie::proof::blinded",
139            account = ?self.account,
140            elapsed = ?start.unwrap().elapsed(),
141            ?path,
142            ?node,
143            ?tree_mask,
144            ?hash_mask,
145            "Blinded node for storage trie"
146        );
147        Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
148    }
149}