Skip to main content

reth_provider/providers/state/
latest.rs

1use crate::{
2    AccountReader, BlockHashReader, HashedPostStateProvider, StateProvider, StateRootProvider,
3};
4use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue, B256};
5use reth_db_api::{cursor::DbDupCursorRO, tables, transaction::DbTx};
6use reth_primitives_traits::{Account, Bytecode};
7use reth_storage_api::{
8    BytecodeReader, DBProvider, StateProofProvider, StorageRootProvider, StorageSettingsCache,
9};
10use reth_storage_errors::provider::{ProviderError, ProviderResult};
11use reth_trie::{
12    proof::{Proof, StorageProof},
13    updates::TrieUpdates,
14    witness::TrieWitness,
15    AccountProof, HashedPostState, HashedStorage, KeccakKeyHasher, MultiProof, MultiProofTargets,
16    StateRoot, StorageMultiProof, StorageRoot, TrieInput, TrieInputSorted,
17};
18use reth_trie_db::{
19    DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot,
20    DatabaseTrieWitness,
21};
22
23/// State provider over latest state that takes tx reference.
24///
25/// Wraps a [`DBProvider`] to get access to database.
26#[derive(Debug)]
27pub struct LatestStateProviderRef<'b, Provider>(&'b Provider);
28
29impl<'b, Provider: DBProvider> LatestStateProviderRef<'b, Provider> {
30    /// Create new state provider
31    pub const fn new(provider: &'b Provider) -> Self {
32        Self(provider)
33    }
34
35    fn tx(&self) -> &Provider::Tx {
36        self.0.tx_ref()
37    }
38
39    fn hashed_storage_lookup(
40        &self,
41        hashed_address: B256,
42        hashed_slot: StorageKey,
43    ) -> ProviderResult<Option<StorageValue>> {
44        let mut cursor = self.tx().cursor_dup_read::<tables::HashedStorages>()?;
45        Ok(cursor
46            .seek_by_key_subkey(hashed_address, hashed_slot)?
47            .filter(|e| e.key == hashed_slot)
48            .map(|e| e.value))
49    }
50}
51
52impl<Provider: DBProvider + StorageSettingsCache> AccountReader
53    for LatestStateProviderRef<'_, Provider>
54{
55    /// Get basic account information.
56    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
57        if self.0.cached_storage_settings().use_hashed_state() {
58            let hashed_address = alloy_primitives::keccak256(address);
59            self.tx()
60                .get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)
61                .map_err(Into::into)
62        } else {
63            self.tx().get_by_encoded_key::<tables::PlainAccountState>(address).map_err(Into::into)
64        }
65    }
66}
67
68impl<Provider: BlockHashReader> BlockHashReader for LatestStateProviderRef<'_, Provider> {
69    /// Get block hash by number.
70    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
71        self.0.block_hash(number)
72    }
73
74    fn canonical_hashes_range(
75        &self,
76        start: BlockNumber,
77        end: BlockNumber,
78    ) -> ProviderResult<Vec<B256>> {
79        self.0.canonical_hashes_range(start, end)
80    }
81}
82
83impl<Provider: DBProvider> StateRootProvider for LatestStateProviderRef<'_, Provider> {
84    fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
85        Ok(StateRoot::overlay_root(self.tx(), &hashed_state.into_sorted())?)
86    }
87
88    fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
89        Ok(StateRoot::overlay_root_from_nodes(self.tx(), TrieInputSorted::from_unsorted(input))?)
90    }
91
92    fn state_root_with_updates(
93        &self,
94        hashed_state: HashedPostState,
95    ) -> ProviderResult<(B256, TrieUpdates)> {
96        Ok(StateRoot::overlay_root_with_updates(self.tx(), &hashed_state.into_sorted())?)
97    }
98
99    fn state_root_from_nodes_with_updates(
100        &self,
101        input: TrieInput,
102    ) -> ProviderResult<(B256, TrieUpdates)> {
103        Ok(StateRoot::overlay_root_from_nodes_with_updates(
104            self.tx(),
105            TrieInputSorted::from_unsorted(input),
106        )?)
107    }
108}
109
110impl<Provider: DBProvider> StorageRootProvider for LatestStateProviderRef<'_, Provider> {
111    fn storage_root(
112        &self,
113        address: Address,
114        hashed_storage: HashedStorage,
115    ) -> ProviderResult<B256> {
116        StorageRoot::overlay_root(self.tx(), address, hashed_storage)
117            .map_err(|err| ProviderError::Database(err.into()))
118    }
119
120    fn storage_proof(
121        &self,
122        address: Address,
123        slot: B256,
124        hashed_storage: HashedStorage,
125    ) -> ProviderResult<reth_trie::StorageProof> {
126        StorageProof::overlay_storage_proof(self.tx(), address, slot, hashed_storage)
127            .map_err(ProviderError::from)
128    }
129
130    fn storage_multiproof(
131        &self,
132        address: Address,
133        slots: &[B256],
134        hashed_storage: HashedStorage,
135    ) -> ProviderResult<StorageMultiProof> {
136        StorageProof::overlay_storage_multiproof(self.tx(), address, slots, hashed_storage)
137            .map_err(ProviderError::from)
138    }
139}
140
141impl<Provider: DBProvider> StateProofProvider for LatestStateProviderRef<'_, Provider> {
142    fn proof(
143        &self,
144        input: TrieInput,
145        address: Address,
146        slots: &[B256],
147    ) -> ProviderResult<AccountProof> {
148        let proof = <Proof<_, _> as DatabaseProof>::from_tx(self.tx());
149        proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
150    }
151
152    fn multiproof(
153        &self,
154        input: TrieInput,
155        targets: MultiProofTargets,
156    ) -> ProviderResult<MultiProof> {
157        let proof = <Proof<_, _> as DatabaseProof>::from_tx(self.tx());
158        proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
159    }
160
161    fn witness(&self, input: TrieInput, target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
162        TrieWitness::overlay_witness(self.tx(), input, target)
163            .map_err(ProviderError::from)
164            .map(|hm| hm.into_values().collect())
165    }
166}
167
168impl<Provider: DBProvider> HashedPostStateProvider for LatestStateProviderRef<'_, Provider> {
169    fn hashed_post_state(&self, bundle_state: &revm_database::BundleState) -> HashedPostState {
170        HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
171    }
172}
173
174impl<Provider: DBProvider + BlockHashReader + StorageSettingsCache> StateProvider
175    for LatestStateProviderRef<'_, Provider>
176{
177    /// Get storage by plain (unhashed) storage key slot.
178    fn storage(
179        &self,
180        account: Address,
181        storage_key: StorageKey,
182    ) -> ProviderResult<Option<StorageValue>> {
183        if self.0.cached_storage_settings().use_hashed_state() {
184            self.hashed_storage_lookup(
185                alloy_primitives::keccak256(account),
186                alloy_primitives::keccak256(storage_key),
187            )
188        } else {
189            let mut cursor = self.tx().cursor_dup_read::<tables::PlainStorageState>()?;
190            if let Some(entry) = cursor.seek_by_key_subkey(account, storage_key)? &&
191                entry.key == storage_key
192            {
193                return Ok(Some(entry.value));
194            }
195            Ok(None)
196        }
197    }
198
199    fn storage_by_hashed_key(
200        &self,
201        address: Address,
202        hashed_storage_key: StorageKey,
203    ) -> ProviderResult<Option<StorageValue>> {
204        if self.0.cached_storage_settings().use_hashed_state() {
205            self.hashed_storage_lookup(alloy_primitives::keccak256(address), hashed_storage_key)
206        } else {
207            Err(ProviderError::UnsupportedProvider)
208        }
209    }
210}
211
212impl<Provider: DBProvider + BlockHashReader> BytecodeReader
213    for LatestStateProviderRef<'_, Provider>
214{
215    /// Get account code by its hash
216    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
217        self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
218    }
219}
220
221/// State provider for the latest state.
222#[derive(Debug)]
223pub struct LatestStateProvider<Provider>(Provider);
224
225impl<Provider: DBProvider> LatestStateProvider<Provider> {
226    /// Create new state provider
227    pub const fn new(db: Provider) -> Self {
228        Self(db)
229    }
230
231    /// Returns a new provider that takes the `TX` as reference
232    #[inline(always)]
233    const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider> {
234        LatestStateProviderRef::new(&self.0)
235    }
236}
237
238// Delegates all provider impls to [LatestStateProviderRef]
239reth_storage_api::macros::delegate_provider_impls!(LatestStateProvider<Provider> where [Provider: DBProvider + BlockHashReader + StorageSettingsCache]);
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244    use crate::test_utils::create_test_provider_factory;
245    use alloy_primitives::{address, b256, keccak256, U256};
246    use reth_db_api::{
247        models::StorageSettings,
248        tables,
249        transaction::{DbTx, DbTxMut},
250    };
251    use reth_primitives_traits::StorageEntry;
252    use reth_storage_api::StorageSettingsCache;
253    use reth_storage_errors::provider::ProviderError;
254
255    const fn assert_state_provider<T: StateProvider>() {}
256    #[expect(dead_code)]
257    const fn assert_latest_state_provider<
258        T: DBProvider + BlockHashReader + StorageSettingsCache,
259    >() {
260        assert_state_provider::<LatestStateProvider<T>>();
261    }
262
263    #[test]
264    fn test_latest_storage_hashed_state() {
265        let factory = create_test_provider_factory();
266        factory.set_storage_settings_cache(StorageSettings::v2());
267
268        let address = address!("0x0000000000000000000000000000000000000001");
269        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
270
271        let hashed_address = keccak256(address);
272        let hashed_slot = keccak256(slot);
273
274        let tx = factory.provider_rw().unwrap().into_tx();
275        tx.put::<tables::HashedStorages>(
276            hashed_address,
277            StorageEntry { key: hashed_slot, value: U256::from(42) },
278        )
279        .unwrap();
280        tx.commit().unwrap();
281
282        let db = factory.provider().unwrap();
283        let provider_ref = LatestStateProviderRef::new(&db);
284
285        assert_eq!(provider_ref.storage(address, slot).unwrap(), Some(U256::from(42)));
286
287        let other_address = address!("0x0000000000000000000000000000000000000099");
288        let other_slot =
289            b256!("0x0000000000000000000000000000000000000000000000000000000000000099");
290        assert_eq!(provider_ref.storage(other_address, other_slot).unwrap(), None);
291
292        let tx = factory.provider_rw().unwrap().into_tx();
293        let plain_address = address!("0x0000000000000000000000000000000000000002");
294        let plain_slot =
295            b256!("0x0000000000000000000000000000000000000000000000000000000000000002");
296        tx.put::<tables::PlainStorageState>(
297            plain_address,
298            StorageEntry { key: plain_slot, value: U256::from(99) },
299        )
300        .unwrap();
301        tx.commit().unwrap();
302
303        let db = factory.provider().unwrap();
304        let provider_ref = LatestStateProviderRef::new(&db);
305        assert_eq!(provider_ref.storage(plain_address, plain_slot).unwrap(), None);
306    }
307
308    #[test]
309    fn test_latest_storage_hashed_state_returns_none_for_missing() {
310        let factory = create_test_provider_factory();
311        factory.set_storage_settings_cache(StorageSettings::v2());
312
313        let address = address!("0x0000000000000000000000000000000000000001");
314        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
315
316        let db = factory.provider().unwrap();
317        let provider_ref = LatestStateProviderRef::new(&db);
318        assert_eq!(provider_ref.storage(address, slot).unwrap(), None);
319    }
320
321    #[test]
322    fn test_latest_storage_legacy() {
323        let factory = create_test_provider_factory();
324        assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
325
326        let address = address!("0x0000000000000000000000000000000000000001");
327        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000005");
328
329        let tx = factory.provider_rw().unwrap().into_tx();
330        tx.put::<tables::PlainStorageState>(
331            address,
332            StorageEntry { key: slot, value: U256::from(42) },
333        )
334        .unwrap();
335        tx.commit().unwrap();
336
337        let db = factory.provider().unwrap();
338        let provider_ref = LatestStateProviderRef::new(&db);
339
340        assert_eq!(provider_ref.storage(address, slot).unwrap(), Some(U256::from(42)));
341
342        let other_slot =
343            b256!("0x0000000000000000000000000000000000000000000000000000000000000099");
344        assert_eq!(provider_ref.storage(address, other_slot).unwrap(), None);
345    }
346
347    #[test]
348    fn test_latest_storage_legacy_does_not_read_hashed() {
349        let factory = create_test_provider_factory();
350        assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
351
352        let address = address!("0x0000000000000000000000000000000000000001");
353        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000005");
354        let hashed_address = keccak256(address);
355        let hashed_slot = keccak256(slot);
356
357        let tx = factory.provider_rw().unwrap().into_tx();
358        tx.put::<tables::HashedStorages>(
359            hashed_address,
360            StorageEntry { key: hashed_slot, value: U256::from(42) },
361        )
362        .unwrap();
363        tx.commit().unwrap();
364
365        let db = factory.provider().unwrap();
366        let provider_ref = LatestStateProviderRef::new(&db);
367        assert_eq!(provider_ref.storage(address, slot).unwrap(), None);
368    }
369
370    #[test]
371    fn test_latest_storage_by_hashed_key_v2() {
372        let factory = create_test_provider_factory();
373        factory.set_storage_settings_cache(StorageSettings::v2());
374
375        let address = address!("0x0000000000000000000000000000000000000001");
376        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
377
378        let hashed_address = keccak256(address);
379        let hashed_slot = keccak256(slot);
380
381        let tx = factory.provider_rw().unwrap().into_tx();
382        tx.put::<tables::HashedStorages>(
383            hashed_address,
384            StorageEntry { key: hashed_slot, value: U256::from(42) },
385        )
386        .unwrap();
387        tx.commit().unwrap();
388
389        let db = factory.provider().unwrap();
390        let provider_ref = LatestStateProviderRef::new(&db);
391
392        assert_eq!(
393            provider_ref.storage_by_hashed_key(address, hashed_slot).unwrap(),
394            Some(U256::from(42))
395        );
396
397        assert_eq!(provider_ref.storage_by_hashed_key(address, slot).unwrap(), None);
398    }
399
400    #[test]
401    fn test_latest_storage_by_hashed_key_unsupported_in_v1() {
402        let factory = create_test_provider_factory();
403        assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
404
405        let address = address!("0x0000000000000000000000000000000000000001");
406        let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
407
408        let db = factory.provider().unwrap();
409        let provider_ref = LatestStateProviderRef::new(&db);
410
411        assert!(matches!(
412            provider_ref.storage_by_hashed_key(address, slot),
413            Err(ProviderError::UnsupportedProvider)
414        ));
415    }
416}