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::{B256HashMap, B256HashSet, 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 TrieAccount,
19};
20
21mod blinded;
22pub use blinded::*;
23
24#[derive(Debug)]
30pub struct Proof<T, H> {
31 trie_cursor_factory: T,
33 hashed_cursor_factory: H,
35 prefix_sets: TriePrefixSetsMut,
37 collect_branch_node_hash_masks: bool,
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_hash_masks: false,
49 }
50 }
51
52 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> Proof<TF, H> {
54 Proof {
55 trie_cursor_factory,
56 hashed_cursor_factory: self.hashed_cursor_factory,
57 prefix_sets: self.prefix_sets,
58 collect_branch_node_hash_masks: self.collect_branch_node_hash_masks,
59 }
60 }
61
62 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> Proof<T, HF> {
64 Proof {
65 trie_cursor_factory: self.trie_cursor_factory,
66 hashed_cursor_factory,
67 prefix_sets: self.prefix_sets,
68 collect_branch_node_hash_masks: self.collect_branch_node_hash_masks,
69 }
70 }
71
72 pub fn with_prefix_sets_mut(mut self, prefix_sets: TriePrefixSetsMut) -> Self {
74 self.prefix_sets = prefix_sets;
75 self
76 }
77
78 pub const fn with_branch_node_hash_masks(mut self, branch_node_hash_masks: bool) -> Self {
80 self.collect_branch_node_hash_masks = branch_node_hash_masks;
81 self
82 }
83}
84
85impl<T, H> Proof<T, H>
86where
87 T: TrieCursorFactory + Clone,
88 H: HashedCursorFactory + Clone,
89{
90 pub fn account_proof(
92 self,
93 address: Address,
94 slots: &[B256],
95 ) -> Result<AccountProof, StateProofError> {
96 Ok(self
97 .multiproof(
98 HashMap::from_iter([(keccak256(address), slots.iter().map(keccak256).collect())])
99 .into(),
100 )?
101 .account_proof(address, slots)?)
102 }
103
104 pub fn multiproof(
106 mut self,
107 mut targets: MultiProofTargets,
108 ) -> Result<MultiProof, StateProofError> {
109 let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
110 let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
111
112 let mut prefix_set = self.prefix_sets.account_prefix_set.clone();
114 prefix_set.extend_keys(targets.keys().map(Nibbles::unpack));
115 let walker = TrieWalker::new(trie_cursor, prefix_set.freeze());
116
117 let retainer = targets.keys().map(Nibbles::unpack).collect();
119 let mut hash_builder = HashBuilder::default()
120 .with_proof_retainer(retainer)
121 .with_updates(self.collect_branch_node_hash_masks);
122
123 let mut storages: B256HashMap<_> =
126 targets.keys().map(|key| (*key, StorageMultiProof::empty())).collect();
127 let mut account_rlp = Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE);
128 let mut account_node_iter = TrieNodeIter::new(walker, hashed_account_cursor);
129 while let Some(account_node) = account_node_iter.try_next()? {
130 match account_node {
131 TrieElement::Branch(node) => {
132 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
133 }
134 TrieElement::Leaf(hashed_address, account) => {
135 let proof_targets = targets.remove(&hashed_address);
136 let leaf_is_proof_target = proof_targets.is_some();
137 let storage_prefix_set = self
138 .prefix_sets
139 .storage_prefix_sets
140 .remove(&hashed_address)
141 .unwrap_or_default();
142 let storage_multiproof = StorageProof::new_hashed(
143 self.trie_cursor_factory.clone(),
144 self.hashed_cursor_factory.clone(),
145 hashed_address,
146 )
147 .with_prefix_set_mut(storage_prefix_set)
148 .with_branch_node_hash_masks(self.collect_branch_node_hash_masks)
149 .storage_multiproof(proof_targets.unwrap_or_default())?;
150
151 account_rlp.clear();
153 let account = TrieAccount::from((account, storage_multiproof.root));
154 account.encode(&mut account_rlp as &mut dyn BufMut);
155
156 hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
157
158 if leaf_is_proof_target {
160 storages.insert(hashed_address, storage_multiproof);
162 }
163 }
164 }
165 }
166 let _ = hash_builder.root();
167 let account_subtree = hash_builder.take_proof_nodes();
168 let branch_node_hash_masks = if self.collect_branch_node_hash_masks {
169 hash_builder
170 .updated_branch_nodes
171 .unwrap_or_default()
172 .into_iter()
173 .map(|(path, node)| (path, node.hash_mask))
174 .collect()
175 } else {
176 HashMap::default()
177 };
178
179 Ok(MultiProof { account_subtree, branch_node_hash_masks, storages })
180 }
181}
182
183#[derive(Debug)]
185pub struct StorageProof<T, H> {
186 trie_cursor_factory: T,
188 hashed_cursor_factory: H,
190 hashed_address: B256,
192 prefix_set: PrefixSetMut,
194 collect_branch_node_hash_masks: bool,
196}
197
198impl<T, H> StorageProof<T, H> {
199 pub fn new(t: T, h: H, address: Address) -> Self {
201 Self::new_hashed(t, h, keccak256(address))
202 }
203
204 pub fn new_hashed(t: T, h: H, hashed_address: B256) -> Self {
206 Self {
207 trie_cursor_factory: t,
208 hashed_cursor_factory: h,
209 hashed_address,
210 prefix_set: PrefixSetMut::default(),
211 collect_branch_node_hash_masks: false,
212 }
213 }
214
215 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageProof<TF, H> {
217 StorageProof {
218 trie_cursor_factory,
219 hashed_cursor_factory: self.hashed_cursor_factory,
220 hashed_address: self.hashed_address,
221 prefix_set: self.prefix_set,
222 collect_branch_node_hash_masks: self.collect_branch_node_hash_masks,
223 }
224 }
225
226 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageProof<T, HF> {
228 StorageProof {
229 trie_cursor_factory: self.trie_cursor_factory,
230 hashed_cursor_factory,
231 hashed_address: self.hashed_address,
232 prefix_set: self.prefix_set,
233 collect_branch_node_hash_masks: self.collect_branch_node_hash_masks,
234 }
235 }
236
237 pub fn with_prefix_set_mut(mut self, prefix_set: PrefixSetMut) -> Self {
239 self.prefix_set = prefix_set;
240 self
241 }
242
243 pub const fn with_branch_node_hash_masks(mut self, branch_node_hash_masks: bool) -> Self {
245 self.collect_branch_node_hash_masks = branch_node_hash_masks;
246 self
247 }
248}
249
250impl<T, H> StorageProof<T, H>
251where
252 T: TrieCursorFactory,
253 H: HashedCursorFactory,
254{
255 pub fn storage_proof(
257 self,
258 slot: B256,
259 ) -> Result<reth_trie_common::StorageProof, StateProofError> {
260 let targets = HashSet::from_iter([keccak256(slot)]);
261 Ok(self.storage_multiproof(targets)?.storage_proof(slot)?)
262 }
263
264 pub fn storage_multiproof(
266 mut self,
267 targets: B256HashSet,
268 ) -> Result<StorageMultiProof, StateProofError> {
269 let mut hashed_storage_cursor =
270 self.hashed_cursor_factory.hashed_storage_cursor(self.hashed_address)?;
271
272 if hashed_storage_cursor.is_storage_empty()? {
274 return Ok(StorageMultiProof::empty())
275 }
276
277 let target_nibbles = targets.into_iter().map(Nibbles::unpack).collect::<Vec<_>>();
278 self.prefix_set.extend_keys(target_nibbles.clone());
279
280 let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?;
281 let walker = TrieWalker::new(trie_cursor, self.prefix_set.freeze());
282
283 let retainer = ProofRetainer::from_iter(target_nibbles);
284 let mut hash_builder = HashBuilder::default()
285 .with_proof_retainer(retainer)
286 .with_updates(self.collect_branch_node_hash_masks);
287 let mut storage_node_iter = TrieNodeIter::new(walker, hashed_storage_cursor);
288 while let Some(node) = storage_node_iter.try_next()? {
289 match node {
290 TrieElement::Branch(node) => {
291 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
292 }
293 TrieElement::Leaf(hashed_slot, value) => {
294 hash_builder.add_leaf(
295 Nibbles::unpack(hashed_slot),
296 alloy_rlp::encode_fixed_size(&value.value).as_ref(),
297 );
298 }
299 }
300 }
301
302 let root = hash_builder.root();
303 let subtree = hash_builder.take_proof_nodes();
304 let branch_node_hash_masks = if self.collect_branch_node_hash_masks {
305 hash_builder
306 .updated_branch_nodes
307 .unwrap_or_default()
308 .into_iter()
309 .map(|(path, node)| (path, node.hash_mask))
310 .collect()
311 } else {
312 HashMap::default()
313 };
314
315 Ok(StorageMultiProof { root, subtree, branch_node_hash_masks })
316 }
317}