reth_provider/providers/state/
latest.rs1use 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#[derive(Debug)]
27pub struct LatestStateProviderRef<'b, Provider>(&'b Provider);
28
29impl<'b, Provider: DBProvider> LatestStateProviderRef<'b, Provider> {
30 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 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 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 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 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#[derive(Debug)]
223pub struct LatestStateProvider<Provider>(Provider);
224
225impl<Provider: DBProvider> LatestStateProvider<Provider> {
226 pub const fn new(db: Provider) -> Self {
228 Self(db)
229 }
230
231 #[inline(always)]
233 const fn as_ref(&self) -> LatestStateProviderRef<'_, Provider> {
234 LatestStateProviderRef::new(&self.0)
235 }
236}
237
238reth_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}