reth_trie/proof/
blinded.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::{prefix_set::TriePrefixSetsMut, MultiProofTargets, Nibbles};
6use reth_trie_sparse::blinded::{
7    pad_path_to_key, BlindedProvider, BlindedProviderFactory, RevealedNode,
8};
9use std::{sync::Arc, time::Instant};
10use tracing::{enabled, trace, Level};
11
12/// Factory for instantiating providers capable of retrieving blinded trie nodes via proofs.
13#[derive(Debug)]
14pub struct ProofBlindedProviderFactory<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    /// A set of prefix sets that have changes.
20    prefix_sets: Arc<TriePrefixSetsMut>,
21}
22
23impl<T, H> ProofBlindedProviderFactory<T, H> {
24    /// Create new proof-based blinded provider factory.
25    pub const fn new(
26        trie_cursor_factory: T,
27        hashed_cursor_factory: H,
28        prefix_sets: Arc<TriePrefixSetsMut>,
29    ) -> Self {
30        Self { trie_cursor_factory, hashed_cursor_factory, prefix_sets }
31    }
32}
33
34impl<T, H> BlindedProviderFactory for ProofBlindedProviderFactory<T, H>
35where
36    T: TrieCursorFactory + Clone + Send + Sync,
37    H: HashedCursorFactory + Clone + Send + Sync,
38{
39    type AccountNodeProvider = ProofBlindedAccountProvider<T, H>;
40    type StorageNodeProvider = ProofBlindedStorageProvider<T, H>;
41
42    fn account_node_provider(&self) -> Self::AccountNodeProvider {
43        ProofBlindedAccountProvider {
44            trie_cursor_factory: self.trie_cursor_factory.clone(),
45            hashed_cursor_factory: self.hashed_cursor_factory.clone(),
46            prefix_sets: self.prefix_sets.clone(),
47        }
48    }
49
50    fn storage_node_provider(&self, account: B256) -> Self::StorageNodeProvider {
51        ProofBlindedStorageProvider {
52            trie_cursor_factory: self.trie_cursor_factory.clone(),
53            hashed_cursor_factory: self.hashed_cursor_factory.clone(),
54            prefix_sets: self.prefix_sets.clone(),
55            account,
56        }
57    }
58}
59
60/// Blinded provider for retrieving account trie nodes by path.
61#[derive(Debug)]
62pub struct ProofBlindedAccountProvider<T, H> {
63    /// The cursor factory for traversing trie nodes.
64    trie_cursor_factory: T,
65    /// The factory for hashed cursors.
66    hashed_cursor_factory: H,
67    /// A set of prefix sets that have changes.
68    prefix_sets: Arc<TriePrefixSetsMut>,
69}
70
71impl<T, H> ProofBlindedAccountProvider<T, H> {
72    /// Create new proof-based blinded account node provider.
73    pub const fn new(
74        trie_cursor_factory: T,
75        hashed_cursor_factory: H,
76        prefix_sets: Arc<TriePrefixSetsMut>,
77    ) -> Self {
78        Self { trie_cursor_factory, hashed_cursor_factory, prefix_sets }
79    }
80}
81
82impl<T, H> BlindedProvider for ProofBlindedAccountProvider<T, H>
83where
84    T: TrieCursorFactory + Clone + Send + Sync,
85    H: HashedCursorFactory + Clone + Send + Sync,
86{
87    fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
88        let start = enabled!(target: "trie::proof::blinded", Level::TRACE).then(Instant::now);
89
90        let targets = MultiProofTargets::from_iter([(pad_path_to_key(path), HashSet::default())]);
91        let mut proof =
92            Proof::new(self.trie_cursor_factory.clone(), self.hashed_cursor_factory.clone())
93                .with_prefix_sets_mut(self.prefix_sets.as_ref().clone())
94                .with_branch_node_masks(true)
95                .multiproof(targets)
96                .map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
97        let node = proof.account_subtree.into_inner().remove(path);
98        let tree_mask = proof.branch_node_tree_masks.remove(path);
99        let hash_mask = proof.branch_node_hash_masks.remove(path);
100
101        trace!(
102            target: "trie::proof::blinded",
103            elapsed = ?start.unwrap().elapsed(),
104            ?path,
105            ?node,
106            ?tree_mask,
107            ?hash_mask,
108            "Blinded node for account trie"
109        );
110        Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
111    }
112}
113
114/// Blinded provider for retrieving storage trie nodes by path.
115#[derive(Debug)]
116pub struct ProofBlindedStorageProvider<T, H> {
117    /// The cursor factory for traversing trie nodes.
118    trie_cursor_factory: T,
119    /// The factory for hashed cursors.
120    hashed_cursor_factory: H,
121    /// A set of prefix sets that have changes.
122    prefix_sets: Arc<TriePrefixSetsMut>,
123    /// Target account.
124    account: B256,
125}
126
127impl<T, H> ProofBlindedStorageProvider<T, H> {
128    /// Create new proof-based blinded storage node provider.
129    pub const fn new(
130        trie_cursor_factory: T,
131        hashed_cursor_factory: H,
132        prefix_sets: Arc<TriePrefixSetsMut>,
133        account: B256,
134    ) -> Self {
135        Self { trie_cursor_factory, hashed_cursor_factory, prefix_sets, account }
136    }
137}
138
139impl<T, H> BlindedProvider for ProofBlindedStorageProvider<T, H>
140where
141    T: TrieCursorFactory + Clone + Send + Sync,
142    H: HashedCursorFactory + Clone + Send + Sync,
143{
144    fn blinded_node(&mut self, path: &Nibbles) -> Result<Option<RevealedNode>, SparseTrieError> {
145        let start = enabled!(target: "trie::proof::blinded", Level::TRACE).then(Instant::now);
146
147        let targets = HashSet::from_iter([pad_path_to_key(path)]);
148        let storage_prefix_set =
149            self.prefix_sets.storage_prefix_sets.get(&self.account).cloned().unwrap_or_default();
150        let mut proof = StorageProof::new_hashed(
151            self.trie_cursor_factory.clone(),
152            self.hashed_cursor_factory.clone(),
153            self.account,
154        )
155        .with_prefix_set_mut(storage_prefix_set)
156        .with_branch_node_masks(true)
157        .storage_multiproof(targets)
158        .map_err(|error| SparseTrieErrorKind::Other(Box::new(error)))?;
159        let node = proof.subtree.into_inner().remove(path);
160        let tree_mask = proof.branch_node_tree_masks.remove(path);
161        let hash_mask = proof.branch_node_hash_masks.remove(path);
162
163        trace!(
164            target: "trie::proof::blinded",
165            account = ?self.account,
166            elapsed = ?start.unwrap().elapsed(),
167            ?path,
168            ?node,
169            ?tree_mask,
170            ?hash_mask,
171            "Blinded node for storage trie"
172        );
173        Ok(node.map(|node| RevealedNode { node, tree_mask, hash_mask }))
174    }
175}