1use crate::{
2 hashed_cursor::{HashedCursorFactory, HashedStorageCursor},
3 node_iter::{TrieElement, TrieNodeIter},
4 prefix_set::{PrefixSetMut, TriePrefixSetsMut},
5 trie_cursor::TrieCursorFactory,
6 walker::TrieWalker,
7 HashBuilder, Nibbles, TRIE_ACCOUNT_RLP_MAX_SIZE,
8};
9use alloy_primitives::{
10 keccak256,
11 map::{B256Map, B256Set, HashMap, HashSet},
12 Address, B256,
13};
14use alloy_rlp::{BufMut, Encodable};
15use reth_execution_errors::trie::StateProofError;
16use reth_trie_common::{
17 proof::ProofRetainer, AccountProof, MultiProof, MultiProofTargets, StorageMultiProof,
18};
19
20mod blinded;
21pub use blinded::*;
22
23#[derive(Debug)]
29pub struct Proof<T, H> {
30 trie_cursor_factory: T,
32 hashed_cursor_factory: H,
34 prefix_sets: TriePrefixSetsMut,
36 collect_branch_node_masks: bool,
38}
39
40impl<T, H> Proof<T, H> {
41 pub fn new(t: T, h: H) -> Self {
43 Self {
44 trie_cursor_factory: t,
45 hashed_cursor_factory: h,
46 prefix_sets: TriePrefixSetsMut::default(),
47 collect_branch_node_masks: false,
48 }
49 }
50
51 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> Proof<TF, H> {
53 Proof {
54 trie_cursor_factory,
55 hashed_cursor_factory: self.hashed_cursor_factory,
56 prefix_sets: self.prefix_sets,
57 collect_branch_node_masks: self.collect_branch_node_masks,
58 }
59 }
60
61 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> Proof<T, HF> {
63 Proof {
64 trie_cursor_factory: self.trie_cursor_factory,
65 hashed_cursor_factory,
66 prefix_sets: self.prefix_sets,
67 collect_branch_node_masks: self.collect_branch_node_masks,
68 }
69 }
70
71 pub fn with_prefix_sets_mut(mut self, prefix_sets: TriePrefixSetsMut) -> Self {
73 self.prefix_sets = prefix_sets;
74 self
75 }
76
77 pub const fn with_branch_node_masks(mut self, branch_node_masks: bool) -> Self {
79 self.collect_branch_node_masks = branch_node_masks;
80 self
81 }
82}
83
84impl<T, H> Proof<T, H>
85where
86 T: TrieCursorFactory + Clone,
87 H: HashedCursorFactory + Clone,
88{
89 pub fn account_proof(
91 self,
92 address: Address,
93 slots: &[B256],
94 ) -> Result<AccountProof, StateProofError> {
95 Ok(self
96 .multiproof(MultiProofTargets::from_iter([(
97 keccak256(address),
98 slots.iter().map(keccak256).collect(),
99 )]))?
100 .account_proof(address, slots)?)
101 }
102
103 pub fn multiproof(
105 mut self,
106 mut targets: MultiProofTargets,
107 ) -> Result<MultiProof, StateProofError> {
108 let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
109 let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
110
111 let mut prefix_set = self.prefix_sets.account_prefix_set.clone();
113 prefix_set.extend_keys(targets.keys().map(Nibbles::unpack));
114 let walker = TrieWalker::state_trie(trie_cursor, prefix_set.freeze());
115
116 let retainer = targets.keys().map(Nibbles::unpack).collect();
118 let mut hash_builder = HashBuilder::default()
119 .with_proof_retainer(retainer)
120 .with_updates(self.collect_branch_node_masks);
121
122 let mut storages: B256Map<_> =
125 targets.keys().map(|key| (*key, StorageMultiProof::empty())).collect();
126 let mut account_rlp = Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE);
127 let mut account_node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor);
128 while let Some(account_node) = account_node_iter.try_next()? {
129 match account_node {
130 TrieElement::Branch(node) => {
131 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
132 }
133 TrieElement::Leaf(hashed_address, account) => {
134 let proof_targets = targets.remove(&hashed_address);
135 let leaf_is_proof_target = proof_targets.is_some();
136 let storage_prefix_set = self
137 .prefix_sets
138 .storage_prefix_sets
139 .remove(&hashed_address)
140 .unwrap_or_default();
141 let storage_multiproof = StorageProof::new_hashed(
142 self.trie_cursor_factory.clone(),
143 self.hashed_cursor_factory.clone(),
144 hashed_address,
145 )
146 .with_prefix_set_mut(storage_prefix_set)
147 .with_branch_node_masks(self.collect_branch_node_masks)
148 .storage_multiproof(proof_targets.unwrap_or_default())?;
149
150 account_rlp.clear();
152 let account = account.into_trie_account(storage_multiproof.root);
153 account.encode(&mut account_rlp as &mut dyn BufMut);
154
155 let is_private = false; hash_builder.add_leaf(
157 Nibbles::unpack(hashed_address),
158 &account_rlp,
159 is_private,
160 );
161
162 if leaf_is_proof_target {
164 storages.insert(hashed_address, storage_multiproof);
166 }
167 }
168 }
169 }
170 let _ = hash_builder.root();
171 let account_subtree = hash_builder.take_proof_nodes();
172 let (branch_node_hash_masks, branch_node_tree_masks) = if self.collect_branch_node_masks {
173 let updated_branch_nodes = hash_builder.updated_branch_nodes.unwrap_or_default();
174 (
175 updated_branch_nodes
176 .iter()
177 .map(|(path, node)| (path.clone(), node.hash_mask))
178 .collect(),
179 updated_branch_nodes
180 .into_iter()
181 .map(|(path, node)| (path, node.tree_mask))
182 .collect(),
183 )
184 } else {
185 (HashMap::default(), HashMap::default())
186 };
187
188 Ok(MultiProof { account_subtree, branch_node_hash_masks, branch_node_tree_masks, storages })
189 }
190}
191
192#[derive(Debug)]
194pub struct StorageProof<T, H> {
195 trie_cursor_factory: T,
197 hashed_cursor_factory: H,
199 hashed_address: B256,
201 prefix_set: PrefixSetMut,
203 collect_branch_node_masks: bool,
205}
206
207impl<T, H> StorageProof<T, H> {
208 pub fn new(t: T, h: H, address: Address) -> Self {
210 Self::new_hashed(t, h, keccak256(address))
211 }
212
213 pub fn new_hashed(t: T, h: H, hashed_address: B256) -> Self {
215 Self {
216 trie_cursor_factory: t,
217 hashed_cursor_factory: h,
218 hashed_address,
219 prefix_set: PrefixSetMut::default(),
220 collect_branch_node_masks: false,
221 }
222 }
223
224 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageProof<TF, H> {
226 StorageProof {
227 trie_cursor_factory,
228 hashed_cursor_factory: self.hashed_cursor_factory,
229 hashed_address: self.hashed_address,
230 prefix_set: self.prefix_set,
231 collect_branch_node_masks: self.collect_branch_node_masks,
232 }
233 }
234
235 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageProof<T, HF> {
237 StorageProof {
238 trie_cursor_factory: self.trie_cursor_factory,
239 hashed_cursor_factory,
240 hashed_address: self.hashed_address,
241 prefix_set: self.prefix_set,
242 collect_branch_node_masks: self.collect_branch_node_masks,
243 }
244 }
245
246 pub fn with_prefix_set_mut(mut self, prefix_set: PrefixSetMut) -> Self {
248 self.prefix_set = prefix_set;
249 self
250 }
251
252 pub const fn with_branch_node_masks(mut self, branch_node_masks: bool) -> Self {
254 self.collect_branch_node_masks = branch_node_masks;
255 self
256 }
257}
258
259impl<T, H> StorageProof<T, H>
260where
261 T: TrieCursorFactory,
262 H: HashedCursorFactory,
263{
264 pub fn storage_proof(
266 self,
267 slot: B256,
268 ) -> Result<reth_trie_common::StorageProof, StateProofError> {
269 let targets = HashSet::from_iter([keccak256(slot)]);
270 Ok(self.storage_multiproof(targets)?.storage_proof(slot)?)
271 }
272
273 pub fn storage_multiproof(
275 mut self,
276 targets: B256Set,
277 ) -> Result<StorageMultiProof, StateProofError> {
278 let mut hashed_storage_cursor =
279 self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
280
281 if hashed_storage_cursor.is_storage_empty()? {
283 return Ok(StorageMultiProof::empty());
284 }
285
286 let target_nibbles = targets.into_iter().map(Nibbles::unpack).collect::<Vec<_>>();
287 self.prefix_set.extend_keys(target_nibbles.clone());
288
289 let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
290 let walker = TrieWalker::storage_trie(trie_cursor, self.prefix_set.freeze());
291
292 let retainer = ProofRetainer::from_iter(target_nibbles);
293 let mut hash_builder = HashBuilder::default()
294 .with_proof_retainer(retainer)
295 .with_updates(self.collect_branch_node_masks);
296 let mut storage_node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor);
297 while let Some(node) = storage_node_iter.try_next()? {
298 match node {
299 TrieElement::Branch(node) => {
300 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
301 }
302 TrieElement::Leaf(hashed_slot, value) => {
303 hash_builder.add_leaf(
304 Nibbles::unpack(hashed_slot),
305 alloy_rlp::encode_fixed_size(&value.value).as_ref(),
306 value.is_private,
307 );
308 }
309 }
310 }
311
312 let root = hash_builder.root();
313 let subtree = hash_builder.take_proof_nodes();
314 let (branch_node_hash_masks, branch_node_tree_masks) = if self.collect_branch_node_masks {
315 let updated_branch_nodes = hash_builder.updated_branch_nodes.unwrap_or_default();
316 (
317 updated_branch_nodes
318 .iter()
319 .map(|(path, node)| (path.clone(), node.hash_mask))
320 .collect(),
321 updated_branch_nodes
322 .into_iter()
323 .map(|(path, node)| (path, node.tree_mask))
324 .collect(),
325 )
326 } else {
327 (HashMap::default(), HashMap::default())
328 };
329
330 Ok(StorageMultiProof { root, subtree, branch_node_hash_masks, branch_node_tree_masks })
331 }
332}