Skip to main content

reth_trie_db/
proof.rs

1use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory, TrieTableAdapter};
2use alloy_primitives::{keccak256, map::HashMap, Address, B256};
3use reth_db_api::transaction::DbTx;
4use reth_execution_errors::StateProofError;
5use reth_trie::{
6    hashed_cursor::HashedPostStateCursorFactory,
7    proof::{Proof, StorageProof},
8    trie_cursor::InMemoryTrieCursorFactory,
9    AccountProof, DecodedMultiProofV2, HashedPostStateSorted, HashedStorage, MultiProof,
10    MultiProofTargets, MultiProofTargetsV2, StorageMultiProof, TrieInput,
11};
12
13/// Extends [`Proof`] with operations specific for working with a database transaction.
14pub trait DatabaseProof<'a> {
15    /// Associated type for the database transaction.
16    type Tx;
17
18    /// Create a new [`Proof`] instance from database transaction.
19    fn from_tx(tx: &'a Self::Tx) -> Self;
20
21    /// Generates the state proof for target account based on [`TrieInput`].
22    fn overlay_account_proof(
23        &self,
24        input: TrieInput,
25        address: Address,
26        slots: &[B256],
27    ) -> Result<AccountProof, StateProofError>;
28
29    /// Generates the state [`MultiProof`] for target hashed account and storage keys.
30    fn overlay_multiproof(
31        &self,
32        input: TrieInput,
33        targets: MultiProofTargets,
34    ) -> Result<MultiProof, StateProofError>;
35
36    /// Generates a V2 decoded state multiproof for target hashed accounts and storage keys.
37    fn overlay_multiproof_v2(
38        &self,
39        input: TrieInput,
40        targets: MultiProofTargetsV2,
41    ) -> Result<DecodedMultiProofV2, StateProofError>;
42}
43
44impl<'a, TX: DbTx, A: TrieTableAdapter> DatabaseProof<'a>
45    for Proof<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>
46{
47    type Tx = TX;
48
49    fn from_tx(tx: &'a Self::Tx) -> Self {
50        Self::new(DatabaseTrieCursorFactory::new(tx), DatabaseHashedCursorFactory::new(tx))
51    }
52    fn overlay_account_proof(
53        &self,
54        input: TrieInput,
55        address: Address,
56        slots: &[B256],
57    ) -> Result<AccountProof, StateProofError> {
58        let nodes_sorted = input.nodes.into_sorted();
59        let state_sorted = input.state.into_sorted();
60        Proof::new(
61            InMemoryTrieCursorFactory::new(self.trie_cursor_factory().clone(), &nodes_sorted),
62            HashedPostStateCursorFactory::new(self.hashed_cursor_factory().clone(), &state_sorted),
63        )
64        .with_prefix_sets_mut(input.prefix_sets)
65        .account_proof(address, slots)
66    }
67
68    fn overlay_multiproof(
69        &self,
70        input: TrieInput,
71        targets: MultiProofTargets,
72    ) -> Result<MultiProof, StateProofError> {
73        let nodes_sorted = input.nodes.into_sorted();
74        let state_sorted = input.state.into_sorted();
75        Proof::new(
76            InMemoryTrieCursorFactory::new(self.trie_cursor_factory().clone(), &nodes_sorted),
77            HashedPostStateCursorFactory::new(self.hashed_cursor_factory().clone(), &state_sorted),
78        )
79        .with_prefix_sets_mut(input.prefix_sets)
80        .multiproof(targets)
81    }
82
83    fn overlay_multiproof_v2(
84        &self,
85        input: TrieInput,
86        targets: MultiProofTargetsV2,
87    ) -> Result<DecodedMultiProofV2, StateProofError> {
88        let nodes_sorted = input.nodes.into_sorted();
89        let state_sorted = input.state.into_sorted();
90        Proof::new(
91            InMemoryTrieCursorFactory::new(self.trie_cursor_factory().clone(), &nodes_sorted),
92            HashedPostStateCursorFactory::new(self.hashed_cursor_factory().clone(), &state_sorted),
93        )
94        .with_prefix_sets_mut(input.prefix_sets)
95        .multiproof_v2(targets)
96    }
97}
98
99/// Extends [`StorageProof`] with operations specific for working with a database transaction.
100pub trait DatabaseStorageProof<'a, TX> {
101    /// Create a new [`StorageProof`] from database transaction and account address.
102    fn from_tx(tx: &'a TX, address: Address) -> Self;
103
104    /// Generates the storage proof for target slot based on [`TrieInput`].
105    fn overlay_storage_proof(
106        tx: &'a TX,
107        address: Address,
108        slot: B256,
109        storage: HashedStorage,
110    ) -> Result<reth_trie::StorageProof, StateProofError>;
111
112    /// Generates the storage multiproof for target slots based on [`TrieInput`].
113    fn overlay_storage_multiproof(
114        tx: &'a TX,
115        address: Address,
116        slots: &[B256],
117        storage: HashedStorage,
118    ) -> Result<StorageMultiProof, StateProofError>;
119}
120
121impl<'a, TX: DbTx, A: TrieTableAdapter> DatabaseStorageProof<'a, TX>
122    for StorageProof<
123        'static,
124        DatabaseTrieCursorFactory<&'a TX, A>,
125        DatabaseHashedCursorFactory<&'a TX>,
126    >
127{
128    fn from_tx(tx: &'a TX, address: Address) -> Self {
129        Self::new(
130            DatabaseTrieCursorFactory::<_, A>::new(tx),
131            DatabaseHashedCursorFactory::new(tx),
132            address,
133        )
134    }
135
136    fn overlay_storage_proof(
137        tx: &'a TX,
138        address: Address,
139        slot: B256,
140        storage: HashedStorage,
141    ) -> Result<reth_trie::StorageProof, StateProofError> {
142        let hashed_address = keccak256(address);
143        let prefix_set = storage.construct_prefix_set();
144        let state_sorted = HashedPostStateSorted::new(
145            Default::default(),
146            HashMap::from_iter([(hashed_address, storage.into_sorted())]),
147        );
148        StorageProof::new(
149            DatabaseTrieCursorFactory::<_, A>::new(tx),
150            HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted),
151            address,
152        )
153        .with_prefix_set_mut(prefix_set)
154        .storage_proof(slot)
155    }
156
157    fn overlay_storage_multiproof(
158        tx: &'a TX,
159        address: Address,
160        slots: &[B256],
161        storage: HashedStorage,
162    ) -> Result<StorageMultiProof, StateProofError> {
163        let hashed_address = keccak256(address);
164        let targets = slots.iter().map(keccak256).collect();
165        let prefix_set = storage.construct_prefix_set();
166        let state_sorted = HashedPostStateSorted::new(
167            Default::default(),
168            HashMap::from_iter([(hashed_address, storage.into_sorted())]),
169        );
170        StorageProof::new(
171            DatabaseTrieCursorFactory::<_, A>::new(tx),
172            HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted),
173            address,
174        )
175        .with_prefix_set_mut(prefix_set)
176        .storage_multiproof(targets)
177    }
178}