1use crate::{BranchNodeMasksMap, Nibbles, ProofTrieNode, TrieAccount};
4use alloc::{borrow::Cow, vec::Vec};
5use alloy_consensus::constants::KECCAK_EMPTY;
6use alloy_primitives::{
7 keccak256,
8 map::{hash_map, B256Map, B256Set},
9 Address, Bytes, B256, U256,
10};
11use alloy_rlp::{encode_fixed_size, Decodable, EMPTY_STRING_CODE};
12use alloy_trie::{
13 nodes::TrieNode,
14 proof::{verify_proof, DecodedProofNodes, ProofNodes, ProofVerificationError},
15 EMPTY_ROOT_HASH,
16};
17use derive_more::{Deref, DerefMut, IntoIterator};
18use itertools::Itertools;
19use reth_primitives_traits::Account;
20
21#[derive(Deref, DerefMut, IntoIterator, Clone, PartialEq, Eq, Default, Debug)]
23pub struct MultiProofTargets(B256Map<B256Set>);
24
25impl FromIterator<(B256, B256Set)> for MultiProofTargets {
26 fn from_iter<T: IntoIterator<Item = (B256, B256Set)>>(iter: T) -> Self {
27 Self(B256Map::from_iter(iter))
28 }
29}
30
31impl MultiProofTargets {
32 pub fn with_capacity(capacity: usize) -> Self {
34 Self(B256Map::with_capacity_and_hasher(capacity, Default::default()))
35 }
36
37 pub fn account(hashed_address: B256) -> Self {
39 Self::accounts([hashed_address])
40 }
41
42 pub fn account_with_slots<I: IntoIterator<Item = B256>>(
44 hashed_address: B256,
45 slots_iter: I,
46 ) -> Self {
47 Self(B256Map::from_iter([(hashed_address, slots_iter.into_iter().collect())]))
48 }
49
50 pub fn accounts<I: IntoIterator<Item = B256>>(iter: I) -> Self {
52 Self(iter.into_iter().map(|hashed_address| (hashed_address, Default::default())).collect())
53 }
54
55 pub fn retain_difference(&mut self, other: &Self) {
58 self.0.retain(|hashed_address, hashed_slots| {
59 if let Some(other_hashed_slots) = other.get(hashed_address) {
60 hashed_slots.retain(|hashed_slot| !other_hashed_slots.contains(hashed_slot));
61 !hashed_slots.is_empty()
62 } else {
63 true
64 }
65 });
66 }
67
68 pub fn extend(&mut self, other: Self) {
70 self.extend_inner(Cow::Owned(other));
71 }
72
73 pub fn extend_ref(&mut self, other: &Self) {
77 self.extend_inner(Cow::Borrowed(other));
78 }
79
80 fn extend_inner(&mut self, other: Cow<'_, Self>) {
81 for (hashed_address, hashed_slots) in other.iter() {
82 self.entry(*hashed_address).or_default().extend(hashed_slots);
83 }
84 }
85
86 pub fn chunks(self, size: usize) -> ChunkedMultiProofTargets {
90 ChunkedMultiProofTargets::new(self, size)
91 }
92
93 pub fn chunking_length(&self) -> usize {
95 self.values().map(|slots| 1 + slots.len().saturating_sub(1)).sum::<usize>()
96 }
97}
98
99#[derive(Debug)]
120pub struct ChunkedMultiProofTargets {
121 flattened_targets: alloc::vec::IntoIter<(B256, Option<B256>)>,
122 size: usize,
123}
124
125impl ChunkedMultiProofTargets {
126 fn new(targets: MultiProofTargets, size: usize) -> Self {
127 let flattened_targets = targets
128 .into_iter()
129 .flat_map(|(address, slots)| {
130 if slots.is_empty() {
131 itertools::Either::Left(core::iter::once((address, None)))
135 } else {
136 itertools::Either::Right(
137 slots.into_iter().map(move |slot| (address, Some(slot))),
138 )
139 }
140 })
141 .sorted_unstable();
142 Self { flattened_targets, size }
143 }
144}
145
146impl Iterator for ChunkedMultiProofTargets {
147 type Item = MultiProofTargets;
148
149 fn next(&mut self) -> Option<Self::Item> {
150 let chunk = self.flattened_targets.by_ref().take(self.size).fold(
151 MultiProofTargets::default(),
152 |mut acc, (address, slot)| {
153 let entry = acc.entry(address).or_default();
154 if let Some(slot) = slot {
155 entry.insert(slot);
156 }
157 acc
158 },
159 );
160
161 if chunk.is_empty() {
162 None
163 } else {
164 Some(chunk)
165 }
166 }
167}
168
169#[derive(Clone, Default, Debug, PartialEq, Eq)]
173pub struct MultiProof {
174 pub account_subtree: ProofNodes,
176 pub branch_node_masks: BranchNodeMasksMap,
179 pub storages: B256Map<StorageMultiProof>,
181}
182
183impl MultiProof {
184 pub fn is_empty(&self) -> bool {
186 self.account_subtree.is_empty() &&
187 self.branch_node_masks.is_empty() &&
188 self.storages.is_empty()
189 }
190
191 pub fn account_proof_nodes(&self, path: &Nibbles) -> Vec<(Nibbles, Bytes)> {
193 self.account_subtree.matching_nodes_sorted(path)
194 }
195
196 pub fn storage_proof_nodes(
198 &self,
199 hashed_address: B256,
200 slots: impl IntoIterator<Item = B256>,
201 ) -> Vec<(B256, Vec<(Nibbles, Bytes)>)> {
202 self.storages
203 .get(&hashed_address)
204 .map(|storage_mp| {
205 slots
206 .into_iter()
207 .map(|slot| {
208 let nibbles = Nibbles::unpack(slot);
209 (slot, storage_mp.subtree.matching_nodes_sorted(&nibbles))
210 })
211 .collect()
212 })
213 .unwrap_or_default()
214 }
215
216 pub fn account_proof(
218 &self,
219 address: Address,
220 slots: &[B256],
221 ) -> Result<AccountProof, alloy_rlp::Error> {
222 let hashed_address = keccak256(address);
223 let nibbles = Nibbles::unpack(hashed_address);
224
225 let proof = self
227 .account_proof_nodes(&nibbles)
228 .into_iter()
229 .map(|(_, node)| node)
230 .collect::<Vec<_>>();
231
232 let info = 'info: {
235 if let Some(last) = proof.last() &&
236 let TrieNode::Leaf(leaf) = TrieNode::decode(&mut &last[..])? &&
237 nibbles.ends_with(&leaf.key)
238 {
239 let account = TrieAccount::decode(&mut &leaf.value[..])?;
240 break 'info Some(Account {
241 balance: account.balance,
242 nonce: account.nonce,
243 bytecode_hash: (account.code_hash != KECCAK_EMPTY).then_some(account.code_hash),
244 })
245 }
246 None
247 };
248
249 let storage_multiproof = self.storages.get(&hashed_address);
251 let storage_root = storage_multiproof.map(|m| m.root).unwrap_or(EMPTY_ROOT_HASH);
252 let mut storage_proofs = Vec::with_capacity(slots.len());
253 for slot in slots {
254 let proof = if let Some(multiproof) = &storage_multiproof {
255 multiproof.storage_proof(*slot)?
256 } else {
257 StorageProof::new(*slot)
258 };
259 storage_proofs.push(proof);
260 }
261 Ok(AccountProof { address, info, proof, storage_root, storage_proofs })
262 }
263
264 pub fn extend(&mut self, other: Self) {
267 self.account_subtree.extend_from(other.account_subtree);
268 self.branch_node_masks.extend(other.branch_node_masks);
269
270 let reserve = if self.storages.is_empty() {
271 other.storages.len()
272 } else {
273 other.storages.len().div_ceil(2)
274 };
275 self.storages.reserve(reserve);
276 for (hashed_address, storage) in other.storages {
277 match self.storages.entry(hashed_address) {
278 hash_map::Entry::Occupied(mut entry) => {
279 debug_assert_eq!(entry.get().root, storage.root);
280 let entry = entry.get_mut();
281 entry.subtree.extend_from(storage.subtree);
282 entry.branch_node_masks.extend(storage.branch_node_masks);
283 }
284 hash_map::Entry::Vacant(entry) => {
285 entry.insert(storage);
286 }
287 }
288 }
289 }
290
291 pub fn from_storage_proof(hashed_address: B256, storage_proof: StorageMultiProof) -> Self {
293 Self {
294 storages: B256Map::from_iter([(hashed_address, storage_proof)]),
295 ..Default::default()
296 }
297 }
298}
299
300#[derive(Clone, Default, Debug, PartialEq, Eq)]
303pub struct DecodedMultiProof {
304 pub account_subtree: DecodedProofNodes,
306 pub branch_node_masks: BranchNodeMasksMap,
309 pub storages: B256Map<DecodedStorageMultiProof>,
311}
312
313impl DecodedMultiProof {
314 pub fn is_empty(&self) -> bool {
316 self.account_subtree.is_empty() &&
317 self.branch_node_masks.is_empty() &&
318 self.storages.is_empty()
319 }
320
321 pub fn account_proof_nodes(&self, path: &Nibbles) -> Vec<(Nibbles, TrieNode)> {
323 self.account_subtree.matching_nodes_sorted(path)
324 }
325
326 pub fn storage_proof_nodes(
328 &self,
329 hashed_address: B256,
330 slots: impl IntoIterator<Item = B256>,
331 ) -> Vec<(B256, Vec<(Nibbles, TrieNode)>)> {
332 self.storages
333 .get(&hashed_address)
334 .map(|storage_mp| {
335 slots
336 .into_iter()
337 .map(|slot| {
338 let nibbles = Nibbles::unpack(slot);
339 (slot, storage_mp.subtree.matching_nodes_sorted(&nibbles))
340 })
341 .collect()
342 })
343 .unwrap_or_default()
344 }
345
346 pub fn account_proof(
348 &self,
349 address: Address,
350 slots: &[B256],
351 ) -> Result<DecodedAccountProof, alloy_rlp::Error> {
352 let hashed_address = keccak256(address);
353 let nibbles = Nibbles::unpack(hashed_address);
354
355 let proof = self
357 .account_proof_nodes(&nibbles)
358 .into_iter()
359 .map(|(_, node)| node)
360 .collect::<Vec<_>>();
361
362 let info = 'info: {
365 if let Some(TrieNode::Leaf(leaf)) = proof.last() &&
366 nibbles.ends_with(&leaf.key)
367 {
368 let account = TrieAccount::decode(&mut &leaf.value[..])?;
369 break 'info Some(Account {
370 balance: account.balance,
371 nonce: account.nonce,
372 bytecode_hash: (account.code_hash != KECCAK_EMPTY).then_some(account.code_hash),
373 })
374 }
375 None
376 };
377
378 let storage_multiproof = self.storages.get(&hashed_address);
380 let storage_root = storage_multiproof.map(|m| m.root).unwrap_or(EMPTY_ROOT_HASH);
381 let mut storage_proofs = Vec::with_capacity(slots.len());
382 for slot in slots {
383 let proof = if let Some(multiproof) = &storage_multiproof {
384 multiproof.storage_proof(*slot)?
385 } else {
386 DecodedStorageProof::new(*slot)
387 };
388 storage_proofs.push(proof);
389 }
390 Ok(DecodedAccountProof { address, info, proof, storage_root, storage_proofs })
391 }
392
393 pub fn extend(&mut self, other: Self) {
396 self.account_subtree.extend_from(other.account_subtree);
397 self.branch_node_masks.extend(other.branch_node_masks);
398
399 let reserve = if self.storages.is_empty() {
400 other.storages.len()
401 } else {
402 other.storages.len().div_ceil(2)
403 };
404 self.storages.reserve(reserve);
405 for (hashed_address, storage) in other.storages {
406 match self.storages.entry(hashed_address) {
407 hash_map::Entry::Occupied(mut entry) => {
408 debug_assert_eq!(entry.get().root, storage.root);
409 let entry = entry.get_mut();
410 entry.subtree.extend_from(storage.subtree);
411 entry.branch_node_masks.extend(storage.branch_node_masks);
412 }
413 hash_map::Entry::Vacant(entry) => {
414 entry.insert(storage);
415 }
416 }
417 }
418 }
419
420 pub fn from_storage_proof(
422 hashed_address: B256,
423 storage_proof: DecodedStorageMultiProof,
424 ) -> Self {
425 Self {
426 storages: B256Map::from_iter([(hashed_address, storage_proof)]),
427 ..Default::default()
428 }
429 }
430}
431
432impl TryFrom<MultiProof> for DecodedMultiProof {
433 type Error = alloy_rlp::Error;
434
435 fn try_from(multi_proof: MultiProof) -> Result<Self, Self::Error> {
436 let account_subtree = DecodedProofNodes::try_from(multi_proof.account_subtree)?;
437 let storages = multi_proof
438 .storages
439 .into_iter()
440 .map(|(address, storage)| Ok((address, storage.try_into()?)))
441 .collect::<Result<B256Map<_>, alloy_rlp::Error>>()?;
442 Ok(Self { account_subtree, branch_node_masks: multi_proof.branch_node_masks, storages })
443 }
444}
445
446#[derive(Clone, Debug, PartialEq, Eq, Default)]
449pub struct DecodedMultiProofV2 {
450 pub account_proofs: Vec<ProofTrieNode>,
452 pub storage_proofs: B256Map<Vec<ProofTrieNode>>,
454}
455
456impl DecodedMultiProofV2 {
457 pub fn is_empty(&self) -> bool {
459 self.account_proofs.is_empty() && self.storage_proofs.is_empty()
460 }
461
462 pub fn extend(&mut self, other: Self) {
466 self.account_proofs.extend(other.account_proofs);
467 for (hashed_address, other_storage_proofs) in other.storage_proofs {
468 match self.storage_proofs.entry(hashed_address) {
469 hash_map::Entry::Vacant(entry) => {
470 entry.insert(other_storage_proofs);
471 }
472 hash_map::Entry::Occupied(mut entry) => {
473 entry.get_mut().extend(other_storage_proofs);
474 }
475 }
476 }
477 }
478}
479
480#[derive(Clone, Debug, PartialEq, Eq)]
482pub struct StorageMultiProof {
483 pub root: B256,
485 pub subtree: ProofNodes,
487 pub branch_node_masks: BranchNodeMasksMap,
490}
491
492impl StorageMultiProof {
493 pub fn empty() -> Self {
495 Self {
496 root: EMPTY_ROOT_HASH,
497 subtree: ProofNodes::from_iter([(
498 Nibbles::default(),
499 Bytes::from([EMPTY_STRING_CODE]),
500 )]),
501 branch_node_masks: BranchNodeMasksMap::default(),
502 }
503 }
504
505 pub fn storage_proof(&self, slot: B256) -> Result<StorageProof, alloy_rlp::Error> {
507 let nibbles = Nibbles::unpack(keccak256(slot));
508
509 let proof = self
511 .subtree
512 .matching_nodes_iter(&nibbles)
513 .sorted_by(|a, b| a.0.cmp(b.0))
514 .map(|(_, node)| node.clone())
515 .collect::<Vec<_>>();
516
517 let value = 'value: {
520 if let Some(last) = proof.last() &&
521 let TrieNode::Leaf(leaf) = TrieNode::decode(&mut &last[..])? &&
522 nibbles.ends_with(&leaf.key)
523 {
524 break 'value U256::decode(&mut &leaf.value[..])?
525 }
526 U256::ZERO
527 };
528
529 Ok(StorageProof { key: slot, nibbles, value, proof })
530 }
531}
532
533#[derive(Clone, Debug, PartialEq, Eq)]
535pub struct DecodedStorageMultiProof {
536 pub root: B256,
538 pub subtree: DecodedProofNodes,
540 pub branch_node_masks: BranchNodeMasksMap,
543}
544
545impl DecodedStorageMultiProof {
546 pub fn empty() -> Self {
548 Self {
549 root: EMPTY_ROOT_HASH,
550 subtree: DecodedProofNodes::from_iter([(Nibbles::default(), TrieNode::EmptyRoot)]),
551 branch_node_masks: BranchNodeMasksMap::default(),
552 }
553 }
554
555 pub fn storage_proof(&self, slot: B256) -> Result<DecodedStorageProof, alloy_rlp::Error> {
557 let nibbles = Nibbles::unpack(keccak256(slot));
558
559 let proof = self
561 .subtree
562 .matching_nodes_iter(&nibbles)
563 .sorted_by(|a, b| a.0.cmp(b.0))
564 .map(|(_, node)| node.clone())
565 .collect::<Vec<_>>();
566
567 let value = 'value: {
570 if let Some(TrieNode::Leaf(leaf)) = proof.last() &&
571 nibbles.ends_with(&leaf.key)
572 {
573 break 'value U256::decode(&mut &leaf.value[..])?
574 }
575 U256::ZERO
576 };
577
578 Ok(DecodedStorageProof { key: slot, nibbles, value, proof })
579 }
580}
581
582impl TryFrom<StorageMultiProof> for DecodedStorageMultiProof {
583 type Error = alloy_rlp::Error;
584
585 fn try_from(multi_proof: StorageMultiProof) -> Result<Self, Self::Error> {
586 let subtree = DecodedProofNodes::try_from(multi_proof.subtree)?;
587 Ok(Self {
588 root: multi_proof.root,
589 subtree,
590 branch_node_masks: multi_proof.branch_node_masks,
591 })
592 }
593}
594
595#[derive(Clone, PartialEq, Eq, Debug)]
597#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
598#[cfg_attr(any(test, feature = "serde"), serde(rename_all = "camelCase"))]
599pub struct AccountProof {
600 pub address: Address,
602 pub info: Option<Account>,
604 pub proof: Vec<Bytes>,
607 pub storage_root: B256,
609 pub storage_proofs: Vec<StorageProof>,
611}
612
613#[cfg(feature = "eip1186")]
614impl AccountProof {
615 pub fn into_eip1186_response(
617 self,
618 slots: Vec<alloy_serde::JsonStorageKey>,
619 ) -> alloy_rpc_types_eth::EIP1186AccountProofResponse {
620 let info = self.info.unwrap_or_default();
621 alloy_rpc_types_eth::EIP1186AccountProofResponse {
622 address: self.address,
623 balance: info.balance,
624 code_hash: info.get_bytecode_hash(),
625 nonce: info.nonce,
626 storage_hash: self.storage_root,
627 account_proof: self.proof,
628 storage_proof: self
629 .storage_proofs
630 .into_iter()
631 .filter_map(|proof| {
632 let input_slot = slots.iter().find(|s| s.as_b256() == proof.key)?;
633 Some(proof.into_eip1186_proof(*input_slot))
634 })
635 .collect(),
636 }
637 }
638
639 pub fn from_eip1186_proof(proof: alloy_rpc_types_eth::EIP1186AccountProofResponse) -> Self {
645 let alloy_rpc_types_eth::EIP1186AccountProofResponse {
646 nonce,
647 address,
648 balance,
649 code_hash,
650 storage_hash,
651 account_proof,
652 storage_proof,
653 ..
654 } = proof;
655 let storage_proofs = storage_proof.into_iter().map(Into::into).collect();
656
657 let (storage_root, info) = if nonce == 0 &&
658 balance.is_zero() &&
659 storage_hash.is_zero() &&
660 code_hash == KECCAK_EMPTY
661 {
662 (EMPTY_ROOT_HASH, None)
665 } else {
666 (storage_hash, Some(Account { nonce, balance, bytecode_hash: code_hash.into() }))
667 };
668
669 Self { address, info, proof: account_proof, storage_root, storage_proofs }
670 }
671}
672
673#[cfg(feature = "eip1186")]
674impl From<alloy_rpc_types_eth::EIP1186AccountProofResponse> for AccountProof {
675 fn from(proof: alloy_rpc_types_eth::EIP1186AccountProofResponse) -> Self {
676 Self::from_eip1186_proof(proof)
677 }
678}
679
680impl Default for AccountProof {
681 fn default() -> Self {
682 Self::new(Address::default())
683 }
684}
685
686impl AccountProof {
687 pub const fn new(address: Address) -> Self {
689 Self {
690 address,
691 info: None,
692 proof: Vec::new(),
693 storage_root: EMPTY_ROOT_HASH,
694 storage_proofs: Vec::new(),
695 }
696 }
697
698 pub fn verify(&self, root: B256) -> Result<(), ProofVerificationError> {
700 for storage_proof in &self.storage_proofs {
702 storage_proof.verify(self.storage_root)?;
703 }
704
705 let expected = if self.info.is_none() && self.storage_root == EMPTY_ROOT_HASH {
707 None
708 } else {
709 Some(alloy_rlp::encode(
710 self.info.unwrap_or_default().into_trie_account(self.storage_root),
711 ))
712 };
713 let nibbles = Nibbles::unpack(keccak256(self.address));
714 verify_proof(root, nibbles, expected, &self.proof)
715 }
716}
717
718#[derive(Clone, PartialEq, Eq, Debug)]
720pub struct DecodedAccountProof {
721 pub address: Address,
723 pub info: Option<Account>,
725 pub proof: Vec<TrieNode>,
728 pub storage_root: B256,
730 pub storage_proofs: Vec<DecodedStorageProof>,
732}
733
734impl Default for DecodedAccountProof {
735 fn default() -> Self {
736 Self::new(Address::default())
737 }
738}
739
740impl DecodedAccountProof {
741 pub const fn new(address: Address) -> Self {
743 Self {
744 address,
745 info: None,
746 proof: Vec::new(),
747 storage_root: EMPTY_ROOT_HASH,
748 storage_proofs: Vec::new(),
749 }
750 }
751}
752
753#[derive(Clone, PartialEq, Eq, Default, Debug)]
755#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))]
756pub struct StorageProof {
757 pub key: B256,
759 pub nibbles: Nibbles,
761 pub value: U256,
763 pub proof: Vec<Bytes>,
766}
767
768impl StorageProof {
769 pub fn new(key: B256) -> Self {
771 let nibbles = Nibbles::unpack(keccak256(key));
772 Self { key, nibbles, ..Default::default() }
773 }
774
775 pub fn new_with_hashed(key: B256, hashed_key: B256) -> Self {
777 Self { key, nibbles: Nibbles::unpack(hashed_key), ..Default::default() }
778 }
779
780 pub fn new_with_nibbles(key: B256, nibbles: Nibbles) -> Self {
782 Self { key, nibbles, ..Default::default() }
783 }
784
785 pub fn with_proof(mut self, proof: Vec<Bytes>) -> Self {
787 self.proof = proof;
788 self
789 }
790
791 pub fn verify(&self, root: B256) -> Result<(), ProofVerificationError> {
793 let expected =
794 if self.value.is_zero() { None } else { Some(encode_fixed_size(&self.value).to_vec()) };
795 verify_proof(root, self.nibbles, expected, &self.proof)
796 }
797}
798
799#[cfg(feature = "eip1186")]
800impl StorageProof {
801 pub fn into_eip1186_proof(
803 self,
804 slot: alloy_serde::JsonStorageKey,
805 ) -> alloy_rpc_types_eth::EIP1186StorageProof {
806 alloy_rpc_types_eth::EIP1186StorageProof { key: slot, value: self.value, proof: self.proof }
807 }
808
809 pub fn from_eip1186_proof(storage_proof: alloy_rpc_types_eth::EIP1186StorageProof) -> Self {
814 Self {
815 value: storage_proof.value,
816 proof: storage_proof.proof,
817 ..Self::new(storage_proof.key.as_b256())
818 }
819 }
820}
821
822#[cfg(feature = "eip1186")]
823impl From<alloy_rpc_types_eth::EIP1186StorageProof> for StorageProof {
824 fn from(proof: alloy_rpc_types_eth::EIP1186StorageProof) -> Self {
825 Self::from_eip1186_proof(proof)
826 }
827}
828
829#[derive(Clone, PartialEq, Eq, Default, Debug)]
831pub struct DecodedStorageProof {
832 pub key: B256,
834 pub nibbles: Nibbles,
836 pub value: U256,
838 pub proof: Vec<TrieNode>,
841}
842
843impl DecodedStorageProof {
844 pub fn new(key: B256) -> Self {
846 let nibbles = Nibbles::unpack(keccak256(key));
847 Self { key, nibbles, ..Default::default() }
848 }
849
850 pub fn new_with_hashed(key: B256, hashed_key: B256) -> Self {
852 Self { key, nibbles: Nibbles::unpack(hashed_key), ..Default::default() }
853 }
854
855 pub fn new_with_nibbles(key: B256, nibbles: Nibbles) -> Self {
857 Self { key, nibbles, ..Default::default() }
858 }
859
860 pub fn with_proof(mut self, proof: Vec<TrieNode>) -> Self {
862 self.proof = proof;
863 self
864 }
865}
866
867#[cfg(any(test, feature = "test-utils"))]
870pub mod triehash {
871 use alloy_primitives::{keccak256, B256};
872 use alloy_rlp::RlpEncodable;
873 use hash_db::Hasher;
874 use plain_hasher::PlainHasher;
875
876 #[derive(Default, Debug, Clone, PartialEq, Eq, RlpEncodable)]
878 #[non_exhaustive]
879 pub struct KeccakHasher;
880
881 #[cfg(any(test, feature = "test-utils"))]
882 impl Hasher for KeccakHasher {
883 type Out = B256;
884 type StdHasher = PlainHasher;
885
886 const LENGTH: usize = 32;
887
888 fn hash(x: &[u8]) -> Self::Out {
889 keccak256(x)
890 }
891 }
892}
893
894#[cfg(test)]
895mod tests {
896 use super::*;
897
898 #[test]
899 fn test_multiproof_extend_account_proofs() {
900 let mut proof1 = MultiProof::default();
901 let mut proof2 = MultiProof::default();
902
903 let addr1 = B256::random();
904 let addr2 = B256::random();
905
906 proof1.account_subtree.insert(
907 Nibbles::unpack(addr1),
908 alloy_rlp::encode_fixed_size(&U256::from(42)).to_vec().into(),
909 );
910 proof2.account_subtree.insert(
911 Nibbles::unpack(addr2),
912 alloy_rlp::encode_fixed_size(&U256::from(43)).to_vec().into(),
913 );
914
915 proof1.extend(proof2);
916
917 assert!(proof1.account_subtree.contains_key(&Nibbles::unpack(addr1)));
918 assert!(proof1.account_subtree.contains_key(&Nibbles::unpack(addr2)));
919 }
920
921 #[test]
922 fn test_multiproof_extend_storage_proofs() {
923 let mut proof1 = MultiProof::default();
924 let mut proof2 = MultiProof::default();
925
926 let addr = B256::random();
927 let root = B256::random();
928
929 let mut subtree1 = ProofNodes::default();
930 subtree1.insert(
931 Nibbles::from_nibbles(vec![0]),
932 alloy_rlp::encode_fixed_size(&U256::from(42)).to_vec().into(),
933 );
934 proof1.storages.insert(
935 addr,
936 StorageMultiProof {
937 root,
938 subtree: subtree1,
939 branch_node_masks: BranchNodeMasksMap::default(),
940 },
941 );
942
943 let mut subtree2 = ProofNodes::default();
944 subtree2.insert(
945 Nibbles::from_nibbles(vec![1]),
946 alloy_rlp::encode_fixed_size(&U256::from(43)).to_vec().into(),
947 );
948 proof2.storages.insert(
949 addr,
950 StorageMultiProof {
951 root,
952 subtree: subtree2,
953 branch_node_masks: BranchNodeMasksMap::default(),
954 },
955 );
956
957 proof1.extend(proof2);
958
959 let storage = proof1.storages.get(&addr).unwrap();
960 assert_eq!(storage.root, root);
961 assert!(storage.subtree.contains_key(&Nibbles::from_nibbles(vec![0])));
962 assert!(storage.subtree.contains_key(&Nibbles::from_nibbles(vec![1])));
963 }
964
965 #[test]
966 fn test_multi_proof_retain_difference() {
967 let mut empty = MultiProofTargets::default();
968 empty.retain_difference(&Default::default());
969 assert!(empty.is_empty());
970
971 let targets = MultiProofTargets::accounts((0..10).map(B256::with_last_byte));
972
973 let mut diffed = targets.clone();
974 diffed.retain_difference(&MultiProofTargets::account(B256::with_last_byte(11)));
975 assert_eq!(diffed, targets);
976
977 diffed.retain_difference(&MultiProofTargets::accounts((0..5).map(B256::with_last_byte)));
978 assert_eq!(diffed, MultiProofTargets::accounts((5..10).map(B256::with_last_byte)));
979
980 diffed.retain_difference(&targets);
981 assert!(diffed.is_empty());
982
983 let mut targets = MultiProofTargets::default();
984 let (account1, account2, account3) =
985 (1..=3).map(B256::with_last_byte).collect_tuple().unwrap();
986 let account2_slots = (1..5).map(B256::with_last_byte).collect::<B256Set>();
987 targets.insert(account1, B256Set::from_iter([B256::with_last_byte(1)]));
988 targets.insert(account2, account2_slots.clone());
989 targets.insert(account3, B256Set::from_iter([B256::with_last_byte(1)]));
990
991 let mut diffed = targets.clone();
992 diffed.retain_difference(&MultiProofTargets::accounts((1..=3).map(B256::with_last_byte)));
993 assert_eq!(diffed, targets);
994
995 let mut account2_slots_expected_len = account2_slots.len();
997 for slot in account2_slots.iter().skip(1) {
998 diffed.retain_difference(&MultiProofTargets::account_with_slots(account2, [*slot]));
999 account2_slots_expected_len -= 1;
1000 assert_eq!(
1001 diffed.get(&account2).map(|slots| slots.len()),
1002 Some(account2_slots_expected_len)
1003 );
1004 }
1005
1006 diffed.retain_difference(&targets);
1007 assert!(diffed.is_empty());
1008 }
1009
1010 #[test]
1011 fn test_multi_proof_retain_difference_no_overlap() {
1012 let mut targets = MultiProofTargets::default();
1013
1014 let (addr1, addr2) = (B256::random(), B256::random());
1016 let (slot1, slot2) = (B256::random(), B256::random());
1017 targets.insert(addr1, std::iter::once(slot1).collect());
1018 targets.insert(addr2, std::iter::once(slot2).collect());
1019
1020 let mut retained = targets.clone();
1021 retained.retain_difference(&Default::default());
1022 assert_eq!(retained, targets);
1023
1024 let mut other_targets = MultiProofTargets::default();
1026 let addr3 = B256::random();
1027 let slot3 = B256::random();
1028 other_targets.insert(addr3, B256Set::from_iter([slot3]));
1029
1030 let mut retained = targets.clone();
1033 retained.retain_difference(&other_targets);
1034 assert_eq!(retained, targets);
1035 }
1036
1037 #[test]
1038 fn test_get_prefetch_proof_targets_remove_subset() {
1039 let mut targets = MultiProofTargets::default();
1041 let (addr1, addr2) = (B256::random(), B256::random());
1042 let (slot1, slot2) = (B256::random(), B256::random());
1043 targets.insert(addr1, B256Set::from_iter([slot1]));
1044 targets.insert(addr2, B256Set::from_iter([slot2]));
1045
1046 let other_targets = MultiProofTargets::account_with_slots(addr1, [slot1]);
1048
1049 let mut retained = targets.clone();
1050 retained.retain_difference(&other_targets);
1051
1052 assert_eq!(retained.len(), 1);
1054 assert!(!retained.contains_key(&addr1));
1055 assert!(retained.contains_key(&addr2));
1056
1057 let slot3 = B256::random();
1059 targets.get_mut(&addr1).unwrap().insert(slot3);
1060
1061 let mut retained = targets.clone();
1062 retained.retain_difference(&other_targets);
1063
1064 assert_eq!(retained.len(), 2);
1067 assert!(retained.contains_key(&addr1));
1068 assert_eq!(retained.get(&addr1), Some(&B256Set::from_iter([slot3])));
1069 assert!(retained.contains_key(&addr2));
1070 assert_eq!(retained.get(&addr2), Some(&B256Set::from_iter([slot2])));
1071 }
1072
1073 #[test]
1074 #[cfg(feature = "eip1186")]
1075 fn eip_1186_roundtrip() {
1076 let mut acc = AccountProof {
1077 address: Address::random(),
1078 info: Some(
1079 Account { nonce: 100, balance: U256::ZERO, bytecode_hash: Some(KECCAK_EMPTY) },
1081 ),
1082 proof: vec![],
1083 storage_root: B256::ZERO,
1084 storage_proofs: vec![],
1085 };
1086
1087 let rpc_proof = acc.clone().into_eip1186_response(Vec::new());
1088 let inverse: AccountProof = rpc_proof.into();
1089 assert_eq!(acc, inverse);
1090
1091 acc.info.as_mut().unwrap().nonce = 0;
1093 let rpc_proof = acc.clone().into_eip1186_response(Vec::new());
1094 let inverse: AccountProof = rpc_proof.into();
1095 acc.info.take();
1096 acc.storage_root = EMPTY_ROOT_HASH;
1097 assert_eq!(acc, inverse);
1098 }
1099
1100 #[test]
1101 fn test_multiproof_targets_chunking_length() {
1102 let mut targets = MultiProofTargets::default();
1103 targets.insert(B256::with_last_byte(1), B256Set::default());
1104 targets.insert(
1105 B256::with_last_byte(2),
1106 B256Set::from_iter([B256::with_last_byte(10), B256::with_last_byte(20)]),
1107 );
1108 targets.insert(
1109 B256::with_last_byte(3),
1110 B256Set::from_iter([
1111 B256::with_last_byte(30),
1112 B256::with_last_byte(31),
1113 B256::with_last_byte(32),
1114 ]),
1115 );
1116
1117 let chunking_length = targets.chunking_length();
1118 for size in 1..=targets.clone().chunks(1).count() {
1119 let chunk_count = targets.clone().chunks(size).count();
1120 let expected_count = chunking_length.div_ceil(size);
1121 assert_eq!(
1122 chunk_count, expected_count,
1123 "chunking_length: {}, size: {}",
1124 chunking_length, size
1125 );
1126 }
1127 }
1128}