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, HashSet},
12 Address, B256,
13};
14use alloy_rlp::{BufMut, Encodable};
15use alloy_trie::proof::AddedRemovedKeys;
16use reth_execution_errors::trie::StateProofError;
17use reth_trie_common::{
18 proof::ProofRetainer, AccountProof, BranchNodeMasks, BranchNodeMasksMap, MultiProof,
19 MultiProofTargets, StorageMultiProof,
20};
21
22#[derive(Debug)]
28pub struct Proof<T, H, K = AddedRemovedKeys> {
29 trie_cursor_factory: T,
31 hashed_cursor_factory: H,
33 prefix_sets: TriePrefixSetsMut,
35 collect_branch_node_masks: bool,
37 added_removed_keys: Option<K>,
39}
40
41impl<T, H> Proof<T, H> {
42 pub fn new(t: T, h: H) -> Self {
44 Self {
45 trie_cursor_factory: t,
46 hashed_cursor_factory: h,
47 prefix_sets: TriePrefixSetsMut::default(),
48 collect_branch_node_masks: false,
49 added_removed_keys: None,
50 }
51 }
52}
53
54impl<T, H, K> Proof<T, H, K> {
55 pub fn with_prefix_sets_mut(mut self, prefix_sets: TriePrefixSetsMut) -> Self {
57 self.prefix_sets = prefix_sets;
58 self
59 }
60
61 pub const fn with_branch_node_masks(mut self, branch_node_masks: bool) -> Self {
63 self.collect_branch_node_masks = branch_node_masks;
64 self
65 }
66
67 pub fn with_added_removed_keys<K2>(self, added_removed_keys: Option<K2>) -> Proof<T, H, K2> {
73 Proof {
74 trie_cursor_factory: self.trie_cursor_factory,
75 hashed_cursor_factory: self.hashed_cursor_factory,
76 prefix_sets: self.prefix_sets,
77 collect_branch_node_masks: self.collect_branch_node_masks,
78 added_removed_keys,
79 }
80 }
81
82 pub const fn trie_cursor_factory(&self) -> &T {
84 &self.trie_cursor_factory
85 }
86
87 pub const fn hashed_cursor_factory(&self) -> &H {
89 &self.hashed_cursor_factory
90 }
91}
92
93impl<T, H, K> Proof<T, H, K>
94where
95 T: TrieCursorFactory + Clone,
96 H: HashedCursorFactory + Clone,
97 K: AsRef<AddedRemovedKeys>,
98{
99 pub fn account_proof(
101 self,
102 address: Address,
103 slots: &[B256],
104 ) -> Result<AccountProof, StateProofError> {
105 Ok(self
106 .multiproof(MultiProofTargets::from_iter([(
107 keccak256(address),
108 slots.iter().map(keccak256).collect(),
109 )]))?
110 .account_proof(address, slots)?)
111 }
112
113 pub fn multiproof(
115 mut self,
116 mut targets: MultiProofTargets,
117 ) -> Result<MultiProof, StateProofError> {
118 let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
119 let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
120
121 let mut prefix_set = self.prefix_sets.account_prefix_set.clone();
123 prefix_set.extend_keys(targets.keys().map(Nibbles::unpack));
124 let walker =
125 TrieWalker::<_, AddedRemovedKeys>::state_trie(trie_cursor, prefix_set.freeze())?
126 .with_added_removed_keys(self.added_removed_keys.as_ref());
127
128 let retainer: ProofRetainer = targets.keys().map(Nibbles::unpack).collect();
130 let retainer = retainer.with_added_removed_keys(self.added_removed_keys.as_ref());
131 let mut hash_builder = HashBuilder::default()
132 .with_proof_retainer(retainer)
133 .with_updates(self.collect_branch_node_masks);
134
135 let mut storages: B256Map<_> =
138 targets.keys().map(|key| (*key, StorageMultiProof::empty())).collect();
139 let mut account_rlp = Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE);
140 let mut account_node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor);
141 while let Some(account_node) = account_node_iter.try_next()? {
142 match account_node {
143 TrieElement::Branch(node) => {
144 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
145 }
146 TrieElement::Leaf(hashed_address, account) => {
147 let proof_targets = targets.remove(&hashed_address);
148 let leaf_is_proof_target = proof_targets.is_some();
149 let collect_storage_masks =
150 self.collect_branch_node_masks && leaf_is_proof_target;
151 let storage_prefix_set = self
152 .prefix_sets
153 .storage_prefix_sets
154 .remove(&hashed_address)
155 .unwrap_or_default();
156 let storage_multiproof = StorageProof::new_hashed(
157 self.trie_cursor_factory.clone(),
158 self.hashed_cursor_factory.clone(),
159 hashed_address,
160 )
161 .with_prefix_set_mut(storage_prefix_set)
162 .with_branch_node_masks(collect_storage_masks)
163 .storage_multiproof(proof_targets.unwrap_or_default())?;
164
165 account_rlp.clear();
167 let account = account.into_trie_account(storage_multiproof.root);
168 account.encode(&mut account_rlp as &mut dyn BufMut);
169
170 hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
171
172 if leaf_is_proof_target {
174 storages.insert(hashed_address, storage_multiproof);
176 }
177 }
178 }
179 }
180 let _ = hash_builder.root();
181 let account_subtree = hash_builder.take_proof_nodes();
182 let branch_node_masks = if self.collect_branch_node_masks {
183 let updated_branch_nodes = hash_builder.updated_branch_nodes.unwrap_or_default();
184 updated_branch_nodes
185 .into_iter()
186 .map(|(path, node)| {
187 (path, BranchNodeMasks { hash_mask: node.hash_mask, tree_mask: node.tree_mask })
188 })
189 .collect()
190 } else {
191 BranchNodeMasksMap::default()
192 };
193
194 Ok(MultiProof { account_subtree, branch_node_masks, storages })
195 }
196}
197
198#[derive(Debug)]
200pub struct StorageProof<T, H, K = AddedRemovedKeys> {
201 trie_cursor_factory: T,
203 hashed_cursor_factory: H,
205 hashed_address: B256,
207 prefix_set: PrefixSetMut,
209 collect_branch_node_masks: bool,
211 added_removed_keys: Option<K>,
213}
214
215impl<T, H> StorageProof<T, H> {
216 pub fn new(t: T, h: H, address: Address) -> Self {
218 Self::new_hashed(t, h, keccak256(address))
219 }
220
221 pub fn new_hashed(t: T, h: H, hashed_address: B256) -> Self {
223 Self {
224 trie_cursor_factory: t,
225 hashed_cursor_factory: h,
226 hashed_address,
227 prefix_set: PrefixSetMut::default(),
228 collect_branch_node_masks: false,
229 added_removed_keys: None,
230 }
231 }
232}
233
234impl<T, H, K> StorageProof<T, H, K> {
235 pub fn with_prefix_set_mut(mut self, prefix_set: PrefixSetMut) -> Self {
237 self.prefix_set = prefix_set;
238 self
239 }
240
241 pub const fn with_branch_node_masks(mut self, branch_node_masks: bool) -> Self {
243 self.collect_branch_node_masks = branch_node_masks;
244 self
245 }
246
247 pub fn with_added_removed_keys<K2>(
253 self,
254 added_removed_keys: Option<K2>,
255 ) -> StorageProof<T, H, K2> {
256 StorageProof {
257 trie_cursor_factory: self.trie_cursor_factory,
258 hashed_cursor_factory: self.hashed_cursor_factory,
259 hashed_address: self.hashed_address,
260 prefix_set: self.prefix_set,
261 collect_branch_node_masks: self.collect_branch_node_masks,
262 added_removed_keys,
263 }
264 }
265}
266
267impl<T, H, K> StorageProof<T, H, K>
268where
269 T: TrieCursorFactory,
270 H: HashedCursorFactory,
271 K: AsRef<AddedRemovedKeys>,
272{
273 pub fn storage_proof(
275 self,
276 slot: B256,
277 ) -> Result<reth_trie_common::StorageProof, StateProofError> {
278 let targets = HashSet::from_iter([keccak256(slot)]);
279 Ok(self.storage_multiproof(targets)?.storage_proof(slot)?)
280 }
281
282 pub fn storage_multiproof(
284 self,
285 targets: B256Set,
286 ) -> Result<StorageMultiProof, StateProofError> {
287 let mut hashed_storage_cursor =
288 self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
289
290 if hashed_storage_cursor.is_storage_empty()? {
292 return Ok(StorageMultiProof::empty())
293 }
294
295 let target_nibbles = targets.into_iter().map(Nibbles::unpack).collect::<Vec<_>>();
296 let mut prefix_set = self.prefix_set;
297 prefix_set.extend_keys(target_nibbles.iter().copied());
298
299 let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
300
301 let walker = TrieWalker::<_>::storage_trie(trie_cursor, prefix_set.freeze())?
302 .with_added_removed_keys(self.added_removed_keys.as_ref());
303
304 let retainer = ProofRetainer::from_iter(target_nibbles)
305 .with_added_removed_keys(self.added_removed_keys.as_ref());
306 let mut hash_builder = HashBuilder::default()
307 .with_proof_retainer(retainer)
308 .with_updates(self.collect_branch_node_masks);
309 let mut storage_node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor);
310 while let Some(node) = storage_node_iter.try_next()? {
311 match node {
312 TrieElement::Branch(node) => {
313 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
314 }
315 TrieElement::Leaf(hashed_slot, value) => {
316 hash_builder.add_leaf(
317 Nibbles::unpack(hashed_slot),
318 alloy_rlp::encode_fixed_size(&value).as_ref(),
319 );
320 }
321 }
322 }
323
324 let root = hash_builder.root();
325 let subtree = hash_builder.take_proof_nodes();
326 let branch_node_masks = if self.collect_branch_node_masks {
327 let updated_branch_nodes = hash_builder.updated_branch_nodes.unwrap_or_default();
328 updated_branch_nodes
329 .into_iter()
330 .map(|(path, node)| {
331 (path, BranchNodeMasks { hash_mask: node.hash_mask, tree_mask: node.tree_mask })
332 })
333 .collect()
334 } else {
335 BranchNodeMasksMap::default()
336 };
337
338 Ok(StorageMultiProof { root, subtree, branch_node_masks })
339 }
340}