Skip to main content

reth_provider/providers/state/
historical.rs

1use crate::{
2    AccountReader, BlockHashReader, ChangeSetReader, EitherReader, HashedPostStateProvider,
3    ProviderError, RocksDBProviderFactory, StateProvider, StateRootProvider,
4};
5use alloy_eips::merge::EPOCH_SLOTS;
6use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue, B256};
7use reth_db_api::{
8    cursor::{DbCursorRO, DbDupCursorRO},
9    table::Table,
10    tables,
11    transaction::DbTx,
12    BlockNumberList,
13};
14use reth_primitives_traits::{Account, Bytecode, NodePrimitives};
15use reth_storage_api::{
16    BlockNumReader, BytecodeReader, DBProvider, NodePrimitivesProvider, PruneCheckpointReader,
17    StageCheckpointReader, StateProofProvider, StorageChangeSetReader, StorageRootProvider,
18    StorageSettingsCache,
19};
20use reth_storage_errors::provider::ProviderResult;
21use reth_storage_overlay::{Overlay, OverlayManager};
22use reth_trie::{
23    hashed_cursor::HashedPostStateCursorFactory,
24    proof::{Proof, StorageProof},
25    trie_cursor::InMemoryTrieCursorFactory,
26    updates::TrieUpdates,
27    witness::TrieWitness,
28    AccountProof, ExecutionWitnessMode, HashedPostState, HashedStorage, KeccakKeyHasher,
29    MultiProof, MultiProofTargets, StateRoot, StorageMultiProof, StorageRoot, TrieInput,
30    TrieInputSorted,
31};
32use reth_trie_db::{DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot};
33
34use std::{fmt::Debug, sync::Arc};
35
36type DbStateRoot<'a, TX, A> = StateRoot<
37    reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
38    reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
39>;
40type DbStorageRoot<'a, TX, A> = StorageRoot<
41    reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
42    reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
43>;
44type DbStorageProof<'a, TX, A> = StorageProof<
45    'static,
46    reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
47    reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
48>;
49type DbProof<'a, TX, A> = Proof<
50    reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
51    reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
52>;
53
54/// Result of a history lookup for an account or storage slot.
55///
56/// Indicates where to find the historical value for a given key at a specific block.
57#[derive(Debug, Eq, PartialEq)]
58pub enum HistoryInfo {
59    /// The key is written to, but only after our block (not yet written at the target block). Or
60    /// it has never been written.
61    NotYetWritten,
62    /// The chunk contains an entry for a write after our block at the given block number.
63    /// The value should be looked up in the changeset at this block.
64    InChangeset(u64),
65    /// The chunk does not contain an entry for a write after our block. This can only
66    /// happen if this is the last chunk, so we need to look in the plain state.
67    InPlainState,
68    /// The key may have been written, but due to pruning we may not have changesets and
69    /// history, so we need to make a plain state lookup.
70    MaybeInPlainState,
71}
72
73impl HistoryInfo {
74    /// Determines where to find the historical value based on computed shard lookup results.
75    ///
76    /// This is a pure function shared by both MDBX and `RocksDB` backends.
77    ///
78    /// # Arguments
79    /// * `found_block` - The block number from the shard lookup
80    /// * `is_before_first_write` - True if the target block is before the first write to this key.
81    ///   This should be computed as: `rank == 0 && found_block != Some(block_number) &&
82    ///   !has_previous_shard` where `has_previous_shard` comes from a lazy `cursor.prev()` check.
83    /// * `lowest_available` - Lowest block where history is available (pruning boundary)
84    pub const fn from_lookup(
85        found_block: Option<u64>,
86        is_before_first_write: bool,
87        lowest_available: Option<BlockNumber>,
88    ) -> Self {
89        if is_before_first_write {
90            if let (Some(_), Some(block_number)) = (lowest_available, found_block) {
91                // The key may have been written, but due to pruning we may not have changesets
92                // and history, so we need to make a changeset lookup.
93                return Self::InChangeset(block_number)
94            }
95            // The key is written to, but only after our block.
96            return Self::NotYetWritten
97        }
98
99        if let Some(block_number) = found_block {
100            // The chunk contains an entry for a write after our block, return it.
101            Self::InChangeset(block_number)
102        } else {
103            // The chunk does not contain an entry for a write after our block. This can only
104            // happen if this is the last chunk and so we need to look in the plain state.
105            Self::InPlainState
106        }
107    }
108}
109
110/// State provider for a given block number which takes a tx reference.
111///
112/// Historical state provider accesses the state at the start of the provided block number.
113/// It means that all changes made in the provided block number are not included.
114///
115/// Historical state provider reads the following tables:
116/// - [`tables::AccountsHistory`]
117/// - [`tables::Bytecodes`]
118/// - [`tables::StoragesHistory`]
119/// - [`tables::AccountChangeSets`]
120/// - [`tables::StorageChangeSets`]
121#[derive(Debug)]
122pub struct HistoricalStateProviderRef<
123    'b,
124    Provider,
125    N: NodePrimitives = <Provider as NodePrimitivesProvider>::Primitives,
126> where
127    Provider: NodePrimitivesProvider<Primitives = N>,
128{
129    /// Database provider
130    provider: &'b Provider,
131    /// Manager for state trie overlays and cached changesets.
132    overlay_manager: OverlayManager<N>,
133    /// Block number is main index for the history state of accounts and storages.
134    block_number: BlockNumber,
135    /// Lowest blocks at which different parts of the state are available.
136    lowest_available_blocks: LowestAvailableBlocks,
137}
138
139impl<'b, Provider, N> HistoricalStateProviderRef<'b, Provider, N>
140where
141    Provider: DBProvider
142        + ChangeSetReader
143        + StorageChangeSetReader
144        + BlockNumReader
145        + NodePrimitivesProvider<Primitives = N>,
146    N: NodePrimitives,
147{
148    /// Create new `StateProvider` for historical block number
149    pub fn new(
150        provider: &'b Provider,
151        block_number: BlockNumber,
152        overlay_manager: OverlayManager<N>,
153    ) -> Self {
154        Self {
155            provider,
156            overlay_manager,
157            block_number,
158            lowest_available_blocks: Default::default(),
159        }
160    }
161
162    /// Create new `StateProvider` for historical block number and lowest block numbers at which
163    /// account & storage histories are available.
164    pub const fn new_with_lowest_available_blocks(
165        provider: &'b Provider,
166        block_number: BlockNumber,
167        lowest_available_blocks: LowestAvailableBlocks,
168        overlay_manager: OverlayManager<N>,
169    ) -> Self {
170        Self { provider, overlay_manager, block_number, lowest_available_blocks }
171    }
172
173    /// Lookup an account in the `AccountsHistory` table using `EitherReader`.
174    pub fn account_history_lookup(&self, address: Address) -> ProviderResult<HistoryInfo>
175    where
176        Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
177    {
178        if !self.lowest_available_blocks.is_account_history_available(self.block_number) {
179            return Err(ProviderError::StateAtBlockPruned(self.block_number))
180        }
181
182        let visible_tip = self.provider.best_block_number()?;
183
184        self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
185            let mut reader = EitherReader::new_accounts_history(self.provider, rocksdb_ref)?;
186            reader.account_history_info(
187                address,
188                self.block_number,
189                self.lowest_available_blocks.account_history_block_number,
190                visible_tip,
191            )
192        })
193    }
194
195    /// Lookup a storage key in the `StoragesHistory` table using `EitherReader`.
196    ///
197    /// `lookup_key` is always a plain (unhashed) storage key.
198    pub fn storage_history_lookup(
199        &self,
200        address: Address,
201        lookup_key: B256,
202    ) -> ProviderResult<HistoryInfo>
203    where
204        Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
205    {
206        if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
207            return Err(ProviderError::StateAtBlockPruned(self.block_number))
208        }
209
210        let visible_tip = self.provider.best_block_number()?;
211
212        self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
213            let mut reader = EitherReader::new_storages_history(self.provider, rocksdb_ref)?;
214            reader.storage_history_info(
215                address,
216                lookup_key,
217                self.block_number,
218                self.lowest_available_blocks.storage_history_block_number,
219                visible_tip,
220            )
221        })
222    }
223
224    /// Resolves a storage value by looking up the given key in history, changesets, or
225    /// plain state.
226    ///
227    /// `lookup_key` is always a plain (unhashed) storage key.
228    fn storage_by_lookup_key(
229        &self,
230        address: Address,
231        lookup_key: B256,
232    ) -> ProviderResult<Option<StorageValue>>
233    where
234        Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
235    {
236        match self.storage_history_lookup(address, lookup_key)? {
237            HistoryInfo::NotYetWritten => Ok(None),
238            HistoryInfo::InChangeset(changeset_block_number) => self
239                .provider
240                .get_storage_before_block(changeset_block_number, address, lookup_key)?
241                .ok_or_else(|| ProviderError::StorageChangesetNotFound {
242                    block_number: changeset_block_number,
243                    address,
244                    storage_key: Box::new(lookup_key),
245                })
246                .map(|entry| entry.value)
247                .map(Some),
248            HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
249                if self.provider.cached_storage_settings().use_hashed_state() {
250                    let hashed_address = alloy_primitives::keccak256(address);
251                    let hashed_slot = alloy_primitives::keccak256(lookup_key);
252                    Ok(self
253                        .tx()
254                        .cursor_dup_read::<tables::HashedStorages>()?
255                        .seek_by_key_subkey(hashed_address, hashed_slot)?
256                        .filter(|entry| entry.key == hashed_slot)
257                        .map(|entry| entry.value)
258                        .or(Some(StorageValue::ZERO)))
259                } else {
260                    Ok(self
261                        .tx()
262                        .cursor_dup_read::<tables::PlainStorageState>()?
263                        .seek_by_key_subkey(address, lookup_key)?
264                        .filter(|entry| entry.key == lookup_key)
265                        .map(|entry| entry.value)
266                        .or(Some(StorageValue::ZERO)))
267                }
268            }
269        }
270    }
271
272    /// Checks and returns `true` if distance to historical block exceeds the provided limit.
273    fn check_distance_against_limit(&self, limit: u64) -> ProviderResult<bool> {
274        let tip = self.provider.last_block_number()?;
275
276        Ok(tip.saturating_sub(self.block_number) > limit)
277    }
278
279    fn build_overlay(&self, input: TrieInputSorted) -> ProviderResult<TrieInputSorted>
280    where
281        Provider:
282            BlockHashReader + PruneCheckpointReader + StageCheckpointReader + StorageSettingsCache,
283    {
284        if self.check_distance_against_limit(EPOCH_SLOTS)? {
285            tracing::warn!(
286                target: "providers::historical_sp",
287                target = self.block_number,
288                "Attempt to calculate state root for an old block might result in OOM"
289            );
290        }
291
292        // Historical providers expose state at the start of `self.block_number`, so the overlay
293        // builder needs the previous canonical block hash to preserve those semantics.
294        let target_block = self.block_number.saturating_sub(1);
295        let anchor_hash = self
296            .provider
297            .block_hash(target_block)?
298            .ok_or_else(|| ProviderError::HeaderNotFound(target_block.into()))?;
299
300        let TrieInputSorted { nodes, state, prefix_sets } = input;
301        let overlay_builder = self
302            .overlay_manager
303            .overlay_builder(anchor_hash)
304            .with_immediate_state_trie_overlay(state, nodes);
305        let Overlay { trie_updates, hashed_post_state } =
306            overlay_builder.build_overlay(self.provider)?;
307
308        Ok(TrieInputSorted::new(trie_updates, hashed_post_state, prefix_sets))
309    }
310
311    /// Set the lowest block number at which the account history is available.
312    pub const fn with_lowest_available_account_history_block_number(
313        mut self,
314        block_number: BlockNumber,
315    ) -> Self {
316        self.lowest_available_blocks.account_history_block_number = Some(block_number);
317        self
318    }
319
320    /// Set the lowest block number at which the storage history is available.
321    pub const fn with_lowest_available_storage_history_block_number(
322        mut self,
323        block_number: BlockNumber,
324    ) -> Self {
325        self.lowest_available_blocks.storage_history_block_number = Some(block_number);
326        self
327    }
328}
329
330impl<Provider, N> HistoricalStateProviderRef<'_, Provider, N>
331where
332    Provider: DBProvider + BlockNumReader + NodePrimitivesProvider<Primitives = N>,
333    N: NodePrimitives,
334{
335    fn tx(&self) -> &Provider::Tx {
336        self.provider.tx_ref()
337    }
338}
339
340impl<Provider, N> AccountReader for HistoricalStateProviderRef<'_, Provider, N>
341where
342    Provider: DBProvider
343        + BlockNumReader
344        + ChangeSetReader
345        + StorageChangeSetReader
346        + StorageSettingsCache
347        + RocksDBProviderFactory
348        + NodePrimitivesProvider<Primitives = N>,
349    N: NodePrimitives,
350{
351    /// Get basic account information.
352    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
353        match self.account_history_lookup(*address)? {
354            HistoryInfo::NotYetWritten => Ok(None),
355            HistoryInfo::InChangeset(changeset_block_number) => {
356                // Use ChangeSetReader trait method to get the account from changesets
357                self.provider
358                    .get_account_before_block(changeset_block_number, *address)?
359                    .ok_or(ProviderError::AccountChangesetNotFound {
360                        block_number: changeset_block_number,
361                        address: *address,
362                    })
363                    .map(|account_before| account_before.info)
364            }
365            HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
366                if self.provider.cached_storage_settings().use_hashed_state() {
367                    let hashed_address = alloy_primitives::keccak256(address);
368                    Ok(self.tx().get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)?)
369                } else {
370                    Ok(self.tx().get_by_encoded_key::<tables::PlainAccountState>(address)?)
371                }
372            }
373        }
374    }
375}
376
377impl<Provider, N> BlockHashReader for HistoricalStateProviderRef<'_, Provider, N>
378where
379    Provider:
380        DBProvider + BlockNumReader + BlockHashReader + NodePrimitivesProvider<Primitives = N>,
381    N: NodePrimitives,
382{
383    /// Get block hash by number.
384    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
385        self.provider.block_hash(number)
386    }
387
388    fn canonical_hashes_range(
389        &self,
390        start: BlockNumber,
391        end: BlockNumber,
392    ) -> ProviderResult<Vec<B256>> {
393        self.provider.canonical_hashes_range(start, end)
394    }
395}
396
397impl<Provider, N> StateRootProvider for HistoricalStateProviderRef<'_, Provider, N>
398where
399    Provider: DBProvider
400        + ChangeSetReader
401        + StorageChangeSetReader
402        + BlockNumReader
403        + BlockHashReader
404        + PruneCheckpointReader
405        + StageCheckpointReader
406        + StorageSettingsCache
407        + NodePrimitivesProvider<Primitives = N>,
408    N: NodePrimitives,
409{
410    fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
411        reth_trie_db::with_adapter!(self.provider, |A| {
412            let input = self.build_overlay(TrieInputSorted::from_unsorted(
413                TrieInput::from_state(hashed_state),
414            ))?;
415            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.tx(), input)?)
416        })
417    }
418
419    fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
420        reth_trie_db::with_adapter!(self.provider, |A| {
421            let input = self.build_overlay(TrieInputSorted::from_unsorted(input))?;
422            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.tx(), input)?)
423        })
424    }
425
426    fn state_root_with_updates(
427        &self,
428        hashed_state: HashedPostState,
429    ) -> ProviderResult<(B256, TrieUpdates)> {
430        reth_trie_db::with_adapter!(self.provider, |A| {
431            let input = self.build_overlay(TrieInputSorted::from_unsorted(
432                TrieInput::from_state(hashed_state),
433            ))?;
434            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(self.tx(), input)?)
435        })
436    }
437
438    fn state_root_from_nodes_with_updates(
439        &self,
440        input: TrieInput,
441    ) -> ProviderResult<(B256, TrieUpdates)> {
442        reth_trie_db::with_adapter!(self.provider, |A| {
443            let input = self.build_overlay(TrieInputSorted::from_unsorted(input))?;
444            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(self.tx(), input)?)
445        })
446    }
447}
448
449impl<Provider, N> StorageRootProvider for HistoricalStateProviderRef<'_, Provider, N>
450where
451    Provider: DBProvider
452        + ChangeSetReader
453        + StorageChangeSetReader
454        + BlockNumReader
455        + BlockHashReader
456        + PruneCheckpointReader
457        + StageCheckpointReader
458        + StorageSettingsCache
459        + NodePrimitivesProvider<Primitives = N>,
460    N: NodePrimitives,
461{
462    fn storage_root(
463        &self,
464        address: Address,
465        hashed_storage: HashedStorage,
466    ) -> ProviderResult<B256> {
467        reth_trie_db::with_adapter!(self.provider, |A| {
468            let input = self.build_overlay(TrieInputSorted::from_unsorted(
469                TrieInput::from_state(HashedPostState::from_hashed_storage(
470                    alloy_primitives::keccak256(address),
471                    hashed_storage,
472                )),
473            ))?;
474            let hashed_storage = input
475                .state
476                .account_storages()
477                .get(&alloy_primitives::keccak256(address))
478                .cloned()
479                .unwrap_or_default()
480                .into();
481            <DbStorageRoot<'_, _, A>>::overlay_root(self.tx(), address, hashed_storage)
482                .map_err(|err| ProviderError::Database(err.into()))
483        })
484    }
485
486    fn storage_proof(
487        &self,
488        address: Address,
489        slot: B256,
490        hashed_storage: HashedStorage,
491    ) -> ProviderResult<reth_trie::StorageProof> {
492        reth_trie_db::with_adapter!(self.provider, |A| {
493            let input = self.build_overlay(TrieInputSorted::from_unsorted(
494                TrieInput::from_state(HashedPostState::from_hashed_storage(
495                    alloy_primitives::keccak256(address),
496                    hashed_storage,
497                )),
498            ))?;
499            let hashed_storage = input
500                .state
501                .account_storages()
502                .get(&alloy_primitives::keccak256(address))
503                .cloned()
504                .unwrap_or_default()
505                .into();
506            <DbStorageProof<'_, _, A>>::overlay_storage_proof(
507                self.tx(),
508                address,
509                slot,
510                hashed_storage,
511            )
512            .map_err(ProviderError::from)
513        })
514    }
515
516    fn storage_multiproof(
517        &self,
518        address: Address,
519        slots: &[B256],
520        hashed_storage: HashedStorage,
521    ) -> ProviderResult<StorageMultiProof> {
522        reth_trie_db::with_adapter!(self.provider, |A| {
523            let input = self.build_overlay(TrieInputSorted::from_unsorted(
524                TrieInput::from_state(HashedPostState::from_hashed_storage(
525                    alloy_primitives::keccak256(address),
526                    hashed_storage,
527                )),
528            ))?;
529            let hashed_storage = input
530                .state
531                .account_storages()
532                .get(&alloy_primitives::keccak256(address))
533                .cloned()
534                .unwrap_or_default()
535                .into();
536            <DbStorageProof<'_, _, A>>::overlay_storage_multiproof(
537                self.tx(),
538                address,
539                slots,
540                hashed_storage,
541            )
542            .map_err(ProviderError::from)
543        })
544    }
545}
546
547impl<Provider, N> StateProofProvider for HistoricalStateProviderRef<'_, Provider, N>
548where
549    Provider: DBProvider
550        + ChangeSetReader
551        + StorageChangeSetReader
552        + BlockNumReader
553        + BlockHashReader
554        + PruneCheckpointReader
555        + StageCheckpointReader
556        + StorageSettingsCache
557        + NodePrimitivesProvider<Primitives = N>,
558    N: NodePrimitives,
559{
560    /// Get account and storage proofs.
561    fn proof(
562        &self,
563        input: TrieInput,
564        address: Address,
565        slots: &[B256],
566    ) -> ProviderResult<AccountProof> {
567        reth_trie_db::with_adapter!(self.provider, |A| {
568            let TrieInputSorted { nodes, state, prefix_sets } =
569                self.build_overlay(TrieInputSorted::from_unsorted(input))?;
570            let input = TrieInput::new(
571                Arc::unwrap_or_clone(nodes).into(),
572                Arc::unwrap_or_clone(state).into(),
573                prefix_sets,
574            );
575            let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
576            proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
577        })
578    }
579
580    fn multiproof(
581        &self,
582        input: TrieInput,
583        targets: MultiProofTargets,
584    ) -> ProviderResult<MultiProof> {
585        reth_trie_db::with_adapter!(self.provider, |A| {
586            let TrieInputSorted { nodes, state, prefix_sets } =
587                self.build_overlay(TrieInputSorted::from_unsorted(input))?;
588            let input = TrieInput::new(
589                Arc::unwrap_or_clone(nodes).into(),
590                Arc::unwrap_or_clone(state).into(),
591                prefix_sets,
592            );
593            let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
594            proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
595        })
596    }
597
598    fn witness(
599        &self,
600        input: TrieInput,
601        target: HashedPostState,
602        mode: ExecutionWitnessMode,
603    ) -> ProviderResult<Vec<Bytes>> {
604        reth_trie_db::with_adapter!(self.provider, |A| {
605            let TrieInputSorted { nodes, state, prefix_sets } =
606                self.build_overlay(TrieInputSorted::from_unsorted(input))?;
607            let witness = TrieWitness::new(
608                InMemoryTrieCursorFactory::new(
609                    reth_trie_db::DatabaseTrieCursorFactory::<_, A>::new(self.tx()),
610                    nodes.as_ref(),
611                ),
612                HashedPostStateCursorFactory::new(
613                    reth_trie_db::DatabaseHashedCursorFactory::new(self.tx()),
614                    state.as_ref(),
615                ),
616            )
617            .with_prefix_sets_mut(prefix_sets)
618            .with_execution_witness_mode(mode);
619            let witness =
620                if mode.is_canonical() { witness } else { witness.always_include_root_node() };
621            witness.compute(target).map_err(ProviderError::from).map(|hm| {
622                let mut values: Vec<_> = hm.into_values().collect();
623                if mode.is_canonical() {
624                    values.sort_unstable();
625                }
626                values
627            })
628        })
629    }
630}
631
632impl<Provider, N> HashedPostStateProvider for HistoricalStateProviderRef<'_, Provider, N>
633where
634    Provider: NodePrimitivesProvider<Primitives = N>,
635    N: NodePrimitives,
636{
637    fn hashed_post_state(&self, bundle_state: &revm::database::BundleState) -> HashedPostState {
638        HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
639    }
640}
641
642impl<Provider, N> StateProvider for HistoricalStateProviderRef<'_, Provider, N>
643where
644    Provider: DBProvider
645        + BlockNumReader
646        + BlockHashReader
647        + ChangeSetReader
648        + StorageChangeSetReader
649        + PruneCheckpointReader
650        + StageCheckpointReader
651        + StorageSettingsCache
652        + RocksDBProviderFactory
653        + NodePrimitivesProvider<Primitives = N>,
654    N: NodePrimitives,
655{
656    /// Expects a plain (unhashed) storage key slot.
657    fn storage(
658        &self,
659        address: Address,
660        storage_key: StorageKey,
661    ) -> ProviderResult<Option<StorageValue>> {
662        self.storage_by_lookup_key(address, storage_key)
663    }
664}
665
666impl<Provider, N> BytecodeReader for HistoricalStateProviderRef<'_, Provider, N>
667where
668    Provider: DBProvider + BlockNumReader + NodePrimitivesProvider<Primitives = N>,
669    N: NodePrimitives,
670{
671    /// Get account code by its hash
672    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
673        self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
674    }
675}
676
677/// State provider for a given block number.
678/// For more detailed description, see [`HistoricalStateProviderRef`].
679#[derive(Debug)]
680pub struct HistoricalStateProvider<Provider: NodePrimitivesProvider> {
681    /// Database provider.
682    provider: Provider,
683    /// Manager for state trie overlays and cached changesets.
684    overlay_manager: OverlayManager<Provider::Primitives>,
685    /// State at the block number is the main indexer of the state.
686    block_number: BlockNumber,
687    /// Lowest blocks at which different parts of the state are available.
688    lowest_available_blocks: LowestAvailableBlocks,
689}
690
691impl<
692        Provider: DBProvider
693            + ChangeSetReader
694            + StorageChangeSetReader
695            + BlockNumReader
696            + NodePrimitivesProvider,
697    > HistoricalStateProvider<Provider>
698{
699    /// Create new `StateProvider` for historical block number
700    pub fn new(
701        provider: Provider,
702        block_number: BlockNumber,
703        overlay_manager: OverlayManager<Provider::Primitives>,
704    ) -> Self {
705        Self {
706            provider,
707            overlay_manager,
708            block_number,
709            lowest_available_blocks: Default::default(),
710        }
711    }
712
713    /// Set the lowest block number at which the account history is available.
714    pub const fn with_lowest_available_account_history_block_number(
715        mut self,
716        block_number: BlockNumber,
717    ) -> Self {
718        self.lowest_available_blocks.account_history_block_number = Some(block_number);
719        self
720    }
721
722    /// Set the lowest block number at which the storage history is available.
723    pub const fn with_lowest_available_storage_history_block_number(
724        mut self,
725        block_number: BlockNumber,
726    ) -> Self {
727        self.lowest_available_blocks.storage_history_block_number = Some(block_number);
728        self
729    }
730}
731
732impl<
733        Provider: DBProvider
734            + ChangeSetReader
735            + StorageChangeSetReader
736            + BlockNumReader
737            + NodePrimitivesProvider,
738    > HistoricalStateProvider<Provider>
739{
740    /// Returns a new provider that takes the `TX` as reference
741    #[inline(always)]
742    fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
743        HistoricalStateProviderRef::new_with_lowest_available_blocks(
744            &self.provider,
745            self.block_number,
746            self.lowest_available_blocks,
747            self.overlay_manager.clone(),
748        )
749    }
750}
751
752// Delegates all provider impls to [HistoricalStateProviderRef]
753reth_storage_api::macros::delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + ChangeSetReader + StorageChangeSetReader + PruneCheckpointReader + StageCheckpointReader + StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider]);
754
755/// Lowest blocks at which different parts of the state are available.
756/// They may be [Some] if pruning is enabled.
757#[derive(Clone, Copy, Debug, Default)]
758pub struct LowestAvailableBlocks {
759    /// Lowest block number at which the account history is available. It may not be available if
760    /// [`reth_prune_types::PruneSegment::AccountHistory`] was pruned.
761    /// [`Option::None`] means all history is available.
762    pub account_history_block_number: Option<BlockNumber>,
763    /// Lowest block number at which the storage history is available. It may not be available if
764    /// [`reth_prune_types::PruneSegment::StorageHistory`] was pruned.
765    /// [`Option::None`] means all history is available.
766    pub storage_history_block_number: Option<BlockNumber>,
767}
768
769impl LowestAvailableBlocks {
770    /// Check if account history is available at the provided block number, i.e. lowest available
771    /// block number for account history is less than or equal to the provided block number.
772    pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
773        self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
774    }
775
776    /// Check if storage history is available at the provided block number, i.e. lowest available
777    /// block number for storage history is less than or equal to the provided block number.
778    pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
779        self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
780    }
781}
782
783/// Computes the rank and finds the next modification block in a history shard.
784///
785/// Given a `block_number`, this function returns:
786/// - `rank`: The number of entries strictly before `block_number` in the shard
787/// - `found_block`: The block number at position `rank` (i.e., the first block >= `block_number`
788///   where a modification occurred), or `None` if `rank` is out of bounds
789///
790/// The rank is adjusted when `block_number` exactly matches an entry in the shard,
791/// so that `found_block` always returns the modification at or after the target.
792///
793/// This logic is shared between MDBX cursor-based lookups and `RocksDB` iterator lookups.
794#[inline]
795pub fn compute_history_rank(
796    chunk: &reth_db_api::BlockNumberList,
797    block_number: BlockNumber,
798) -> (u64, Option<u64>) {
799    let mut rank = chunk.rank(block_number);
800    // `rank(block_number)` returns count of entries <= block_number.
801    // We want the first entry >= block_number, so if block_number is in the shard,
802    // we need to step back one position to point at it (not past it).
803    if rank.checked_sub(1).and_then(|r| chunk.select(r)) == Some(block_number) {
804        rank -= 1;
805    }
806    (rank, chunk.select(rank))
807}
808
809/// Checks if a previous shard lookup is needed to determine if we're before the first write.
810///
811/// Returns `true` when `rank == 0` (first entry in shard) and the found block doesn't match
812/// the target block number. In this case, we need to check if there's a previous shard.
813#[inline]
814pub fn needs_prev_shard_check(
815    rank: u64,
816    found_block: Option<u64>,
817    block_number: BlockNumber,
818) -> bool {
819    rank == 0 && found_block != Some(block_number)
820}
821
822/// Generic history lookup for sharded history tables.
823///
824/// Seeks to the shard containing `block_number`, verifies the key via `key_filter`,
825/// and checks previous shard to detect if we're before the first write.
826pub fn history_info<T, K, C>(
827    cursor: &mut C,
828    key: K,
829    block_number: BlockNumber,
830    key_filter: impl Fn(&K) -> bool,
831    lowest_available_block_number: Option<BlockNumber>,
832) -> ProviderResult<HistoryInfo>
833where
834    T: Table<Key = K, Value = BlockNumberList>,
835    C: DbCursorRO<T>,
836{
837    // Lookup the history chunk in the history index. If the key does not appear in the
838    // index, the first chunk for the next key will be returned so we filter out chunks that
839    // have a different key.
840    if let Some(chunk) = cursor.seek(key)?.filter(|(k, _)| key_filter(k)).map(|x| x.1) {
841        let (rank, found_block) = compute_history_rank(&chunk, block_number);
842
843        // If our block is before the first entry in the index chunk and this first entry
844        // doesn't equal to our block, it might be before the first write ever. To check, we
845        // look at the previous entry and check if the key is the same.
846        // This check is worth it, the `cursor.prev()` check is rarely triggered (the if will
847        // short-circuit) and when it passes we save a full seek into the changeset/plain state
848        // table.
849        let is_before_first_write = needs_prev_shard_check(rank, found_block, block_number) &&
850            !cursor.prev()?.is_some_and(|(k, _)| key_filter(&k));
851
852        Ok(HistoryInfo::from_lookup(
853            found_block,
854            is_before_first_write,
855            lowest_available_block_number,
856        ))
857    } else if lowest_available_block_number.is_some() {
858        // The key may have been written, but due to pruning we may not have changesets and
859        // history, so we need to make a plain state lookup.
860        Ok(HistoryInfo::MaybeInPlainState)
861    } else {
862        // The key has not been written to at all.
863        Ok(HistoryInfo::NotYetWritten)
864    }
865}
866
867#[cfg(test)]
868mod tests {
869    use super::needs_prev_shard_check;
870    use crate::{
871        providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
872        test_utils::create_test_provider_factory,
873        AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, RocksDBProviderFactory,
874        StateProvider,
875    };
876    use alloy_primitives::{address, b256, Address, B256, U256};
877    use reth_db_api::{
878        models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
879        tables,
880        transaction::{DbTx, DbTxMut},
881        BlockNumberList,
882    };
883    use reth_primitives_traits::{Account, StorageEntry};
884    use reth_storage_api::{
885        BlockHashReader, BlockNumReader, ChangeSetReader, DBProvider, DatabaseProviderFactory,
886        NodePrimitivesProvider, PruneCheckpointReader, StageCheckpointReader,
887        StorageChangeSetReader, StorageSettingsCache,
888    };
889    use reth_storage_errors::provider::ProviderError;
890    use reth_storage_overlay::OverlayManager;
891
892    const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
893    const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
894    const STORAGE: B256 =
895        b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
896
897    const fn assert_state_provider<T: StateProvider>() {}
898    #[expect(dead_code)]
899    const fn assert_historical_state_provider<
900        T: DBProvider
901            + BlockNumReader
902            + BlockHashReader
903            + ChangeSetReader
904            + StorageChangeSetReader
905            + PruneCheckpointReader
906            + StageCheckpointReader
907            + StorageSettingsCache
908            + RocksDBProviderFactory
909            + NodePrimitivesProvider,
910    >() {
911        assert_state_provider::<HistoricalStateProvider<T>>();
912    }
913
914    #[test]
915    fn history_provider_get_account() {
916        let factory = create_test_provider_factory();
917        let tx = factory.provider_rw().unwrap().into_tx();
918
919        tx.put::<tables::AccountsHistory>(
920            ShardedKey { key: ADDRESS, highest_block_number: 7 },
921            BlockNumberList::new([1, 3, 7]).unwrap(),
922        )
923        .unwrap();
924        tx.put::<tables::AccountsHistory>(
925            ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
926            BlockNumberList::new([10, 15]).unwrap(),
927        )
928        .unwrap();
929        tx.put::<tables::AccountsHistory>(
930            ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
931            BlockNumberList::new([4]).unwrap(),
932        )
933        .unwrap();
934
935        let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
936        let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
937        let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
938        let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
939        let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
940
941        let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
942
943        // setup
944        tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
945            .unwrap();
946        tx.put::<tables::AccountChangeSets>(
947            3,
948            AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
949        )
950        .unwrap();
951        tx.put::<tables::AccountChangeSets>(
952            4,
953            AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
954        )
955        .unwrap();
956        tx.put::<tables::AccountChangeSets>(
957            7,
958            AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
959        )
960        .unwrap();
961        tx.put::<tables::AccountChangeSets>(
962            10,
963            AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
964        )
965        .unwrap();
966        tx.put::<tables::AccountChangeSets>(
967            15,
968            AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
969        )
970        .unwrap();
971
972        // setup plain state
973        tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
974        tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
975        tx.commit().unwrap();
976
977        let db = factory.provider().unwrap();
978
979        // run
980        assert!(matches!(
981            HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
982                .basic_account(&ADDRESS),
983            Ok(None)
984        ));
985        assert!(matches!(
986            HistoricalStateProviderRef::new(&db, 2, OverlayManager::default()).basic_account(&ADDRESS),
987            Ok(Some(acc)) if acc == acc_at3
988        ));
989        assert!(matches!(
990            HistoricalStateProviderRef::new(&db, 3, OverlayManager::default()).basic_account(&ADDRESS),
991            Ok(Some(acc)) if acc == acc_at3
992        ));
993        assert!(matches!(
994            HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).basic_account(&ADDRESS),
995            Ok(Some(acc)) if acc == acc_at7
996        ));
997        assert!(matches!(
998            HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).basic_account(&ADDRESS),
999            Ok(Some(acc)) if acc == acc_at7
1000        ));
1001        assert!(matches!(
1002            HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).basic_account(&ADDRESS),
1003            Ok(Some(acc)) if acc == acc_at10
1004        ));
1005        assert!(matches!(
1006            HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).basic_account(&ADDRESS),
1007            Ok(Some(acc)) if acc == acc_at10
1008        ));
1009        assert!(matches!(
1010            HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).basic_account(&ADDRESS),
1011            Ok(Some(acc)) if acc == acc_at15
1012        ));
1013        assert!(matches!(
1014            HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).basic_account(&ADDRESS),
1015            Ok(Some(acc)) if acc == acc_plain
1016        ));
1017
1018        assert!(matches!(
1019            HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1020                .basic_account(&HIGHER_ADDRESS),
1021            Ok(None)
1022        ));
1023        assert!(matches!(
1024            HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).basic_account(&HIGHER_ADDRESS),
1025            Ok(Some(acc)) if acc == higher_acc_plain
1026        ));
1027    }
1028
1029    #[test]
1030    fn history_provider_get_storage() {
1031        let factory = create_test_provider_factory();
1032        let tx = factory.provider_rw().unwrap().into_tx();
1033
1034        tx.put::<tables::StoragesHistory>(
1035            StorageShardedKey {
1036                address: ADDRESS,
1037                sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1038            },
1039            BlockNumberList::new([3, 7]).unwrap(),
1040        )
1041        .unwrap();
1042        tx.put::<tables::StoragesHistory>(
1043            StorageShardedKey {
1044                address: ADDRESS,
1045                sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1046            },
1047            BlockNumberList::new([10, 15]).unwrap(),
1048        )
1049        .unwrap();
1050        tx.put::<tables::StoragesHistory>(
1051            StorageShardedKey {
1052                address: HIGHER_ADDRESS,
1053                sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1054            },
1055            BlockNumberList::new([4]).unwrap(),
1056        )
1057        .unwrap();
1058
1059        let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1060        let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1061        let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1062        let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1063        let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1064        let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1065        let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1066
1067        // setup
1068        tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1069        tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1070        tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1071        tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1072        tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1073
1074        // setup plain state
1075        tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1076        tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1077        tx.commit().unwrap();
1078
1079        let db = factory.provider().unwrap();
1080
1081        // run
1082        assert!(matches!(
1083            HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1084                .storage(ADDRESS, STORAGE),
1085            Ok(None)
1086        ));
1087        assert!(matches!(
1088            HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1089                .storage(ADDRESS, STORAGE),
1090            Ok(Some(U256::ZERO))
1091        ));
1092        assert!(matches!(
1093            HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1094            Ok(Some(expected_value)) if expected_value == entry_at7.value
1095        ));
1096        assert!(matches!(
1097            HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1098            Ok(Some(expected_value)) if expected_value == entry_at7.value
1099        ));
1100        assert!(matches!(
1101            HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1102            Ok(Some(expected_value)) if expected_value == entry_at10.value
1103        ));
1104        assert!(matches!(
1105            HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1106            Ok(Some(expected_value)) if expected_value == entry_at10.value
1107        ));
1108        assert!(matches!(
1109            HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1110            Ok(Some(expected_value)) if expected_value == entry_at15.value
1111        ));
1112        assert!(matches!(
1113            HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1114            Ok(Some(expected_value)) if expected_value == entry_plain.value
1115        ));
1116        assert!(matches!(
1117            HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1118                .storage(HIGHER_ADDRESS, STORAGE),
1119            Ok(None)
1120        ));
1121        assert!(matches!(
1122            HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1123            Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1124        ));
1125    }
1126
1127    #[test]
1128    fn history_provider_unavailable() {
1129        let factory = create_test_provider_factory();
1130        let db = factory.database_provider_rw().unwrap();
1131
1132        // provider block_number < lowest available block number,
1133        // i.e. state at provider block is pruned
1134        let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1135            &db,
1136            2,
1137            LowestAvailableBlocks {
1138                account_history_block_number: Some(3),
1139                storage_history_block_number: Some(3),
1140            },
1141            OverlayManager::default(),
1142        );
1143        assert!(matches!(
1144            provider.account_history_lookup(ADDRESS),
1145            Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1146        ));
1147        assert!(matches!(
1148            provider.storage_history_lookup(ADDRESS, STORAGE),
1149            Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1150        ));
1151
1152        // provider block_number == lowest available block number,
1153        // i.e. state at provider block is available
1154        let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1155            &db,
1156            2,
1157            LowestAvailableBlocks {
1158                account_history_block_number: Some(2),
1159                storage_history_block_number: Some(2),
1160            },
1161            OverlayManager::default(),
1162        );
1163        assert!(matches!(
1164            provider.account_history_lookup(ADDRESS),
1165            Ok(HistoryInfo::MaybeInPlainState)
1166        ));
1167        assert!(matches!(
1168            provider.storage_history_lookup(ADDRESS, STORAGE),
1169            Ok(HistoryInfo::MaybeInPlainState)
1170        ));
1171
1172        // provider block_number == lowest available block number,
1173        // i.e. state at provider block is available
1174        let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1175            &db,
1176            2,
1177            LowestAvailableBlocks {
1178                account_history_block_number: Some(1),
1179                storage_history_block_number: Some(1),
1180            },
1181            OverlayManager::default(),
1182        );
1183        assert!(matches!(
1184            provider.account_history_lookup(ADDRESS),
1185            Ok(HistoryInfo::MaybeInPlainState)
1186        ));
1187        assert!(matches!(
1188            provider.storage_history_lookup(ADDRESS, STORAGE),
1189            Ok(HistoryInfo::MaybeInPlainState)
1190        ));
1191    }
1192
1193    #[test]
1194    fn test_history_info_from_lookup() {
1195        // Before first write, no pruning → not yet written
1196        assert_eq!(HistoryInfo::from_lookup(Some(10), true, None), HistoryInfo::NotYetWritten);
1197        assert_eq!(HistoryInfo::from_lookup(None, true, None), HistoryInfo::NotYetWritten);
1198
1199        // Before first write WITH pruning → check changeset (pruning may have removed history)
1200        assert_eq!(HistoryInfo::from_lookup(Some(10), true, Some(5)), HistoryInfo::InChangeset(10));
1201        assert_eq!(HistoryInfo::from_lookup(None, true, Some(5)), HistoryInfo::NotYetWritten);
1202
1203        // Not before first write → check changeset or plain state
1204        assert_eq!(HistoryInfo::from_lookup(Some(10), false, None), HistoryInfo::InChangeset(10));
1205        assert_eq!(HistoryInfo::from_lookup(None, false, None), HistoryInfo::InPlainState);
1206    }
1207
1208    #[test]
1209    fn history_provider_get_storage_legacy() {
1210        let factory = create_test_provider_factory();
1211
1212        assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
1213
1214        let tx = factory.provider_rw().unwrap().into_tx();
1215
1216        tx.put::<tables::StoragesHistory>(
1217            StorageShardedKey {
1218                address: ADDRESS,
1219                sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1220            },
1221            BlockNumberList::new([3, 7]).unwrap(),
1222        )
1223        .unwrap();
1224        tx.put::<tables::StoragesHistory>(
1225            StorageShardedKey {
1226                address: ADDRESS,
1227                sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1228            },
1229            BlockNumberList::new([10, 15]).unwrap(),
1230        )
1231        .unwrap();
1232        tx.put::<tables::StoragesHistory>(
1233            StorageShardedKey {
1234                address: HIGHER_ADDRESS,
1235                sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1236            },
1237            BlockNumberList::new([4]).unwrap(),
1238        )
1239        .unwrap();
1240
1241        let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1242        let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1243        let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1244        let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1245        let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1246        let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1247        let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1248
1249        tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1250        tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1251        tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1252        tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1253        tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1254
1255        tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1256        tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1257        tx.commit().unwrap();
1258
1259        let db = factory.provider().unwrap();
1260
1261        assert!(matches!(
1262            HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1263                .storage(ADDRESS, STORAGE),
1264            Ok(None)
1265        ));
1266        assert!(matches!(
1267            HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1268                .storage(ADDRESS, STORAGE),
1269            Ok(Some(U256::ZERO))
1270        ));
1271        assert!(matches!(
1272            HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1273            Ok(Some(expected_value)) if expected_value == entry_at7.value
1274        ));
1275        assert!(matches!(
1276            HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1277            Ok(Some(expected_value)) if expected_value == entry_at7.value
1278        ));
1279        assert!(matches!(
1280            HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1281            Ok(Some(expected_value)) if expected_value == entry_at10.value
1282        ));
1283        assert!(matches!(
1284            HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1285            Ok(Some(expected_value)) if expected_value == entry_at10.value
1286        ));
1287        assert!(matches!(
1288            HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1289            Ok(Some(expected_value)) if expected_value == entry_at15.value
1290        ));
1291        assert!(matches!(
1292            HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1293            Ok(Some(expected_value)) if expected_value == entry_plain.value
1294        ));
1295        assert!(matches!(
1296            HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1297                .storage(HIGHER_ADDRESS, STORAGE),
1298            Ok(None)
1299        ));
1300        assert!(matches!(
1301            HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1302            Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1303        ));
1304    }
1305
1306    #[test]
1307    fn history_provider_get_storage_hashed_state() {
1308        use crate::BlockWriter;
1309        use alloy_primitives::keccak256;
1310        use reth_db_api::models::StorageSettings;
1311        use reth_execution_types::ExecutionOutcome;
1312        use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1313        use revm::database::BundleState;
1314        use std::collections::HashMap;
1315
1316        let factory = create_test_provider_factory();
1317        factory.set_storage_settings_cache(StorageSettings::v2());
1318
1319        let slot = U256::from_be_bytes(*STORAGE);
1320        let account: revm::state::AccountInfo =
1321            Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }.into();
1322        let higher_account: revm::state::AccountInfo =
1323            Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None }.into();
1324
1325        let mut rng = generators::rng();
1326        let blocks = random_block_range(
1327            &mut rng,
1328            0..=15,
1329            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1330        );
1331
1332        let mut addr_storage = HashMap::default();
1333        addr_storage.insert(slot, (U256::ZERO, U256::from(100)));
1334        let mut higher_storage = HashMap::default();
1335        higher_storage.insert(slot, (U256::ZERO, U256::from(1000)));
1336
1337        type Revert = Vec<(Address, Option<Option<revm::state::AccountInfo>>, Vec<(U256, U256)>)>;
1338        let mut reverts: Vec<Revert> = vec![Vec::new(); 16];
1339
1340        reverts[3] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::ZERO)])];
1341        reverts[4] =
1342            vec![(HIGHER_ADDRESS, Some(Some(higher_account.clone())), vec![(slot, U256::ZERO)])];
1343        reverts[7] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(7))])];
1344        reverts[10] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(10))])];
1345        reverts[15] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(15))])];
1346
1347        let bundle = BundleState::new(
1348            [
1349                (ADDRESS, None, Some(account), addr_storage),
1350                (HIGHER_ADDRESS, None, Some(higher_account), higher_storage),
1351            ],
1352            reverts,
1353            [],
1354        );
1355
1356        let provider_rw = factory.provider_rw().unwrap();
1357        provider_rw
1358            .append_blocks_with_state(
1359                blocks
1360                    .into_iter()
1361                    .map(|b| b.try_recover().expect("failed to seal block with senders"))
1362                    .collect(),
1363                &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1364                Default::default(),
1365            )
1366            .unwrap();
1367
1368        let hashed_address = keccak256(ADDRESS);
1369        let hashed_higher_address = keccak256(HIGHER_ADDRESS);
1370        let hashed_storage = keccak256(STORAGE);
1371
1372        provider_rw
1373            .tx_ref()
1374            .put::<tables::HashedStorages>(
1375                hashed_address,
1376                StorageEntry { key: hashed_storage, value: U256::from(100) },
1377            )
1378            .unwrap();
1379        provider_rw
1380            .tx_ref()
1381            .put::<tables::HashedStorages>(
1382                hashed_higher_address,
1383                StorageEntry { key: hashed_storage, value: U256::from(1000) },
1384            )
1385            .unwrap();
1386        provider_rw
1387            .tx_ref()
1388            .put::<tables::HashedAccounts>(
1389                hashed_address,
1390                Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None },
1391            )
1392            .unwrap();
1393        provider_rw
1394            .tx_ref()
1395            .put::<tables::HashedAccounts>(
1396                hashed_higher_address,
1397                Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None },
1398            )
1399            .unwrap();
1400        provider_rw.commit().unwrap();
1401
1402        let db = factory.provider().unwrap();
1403
1404        assert!(matches!(
1405            HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1406                .storage(ADDRESS, STORAGE),
1407            Ok(None)
1408        ));
1409        assert!(matches!(
1410            HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1411                .storage(ADDRESS, STORAGE),
1412            Ok(Some(U256::ZERO))
1413        ));
1414        assert!(matches!(
1415            HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1416            Ok(Some(v)) if v == U256::from(7)
1417        ));
1418        assert!(matches!(
1419            HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1420            Ok(Some(v)) if v == U256::from(7)
1421        ));
1422        assert!(matches!(
1423            HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1424            Ok(Some(v)) if v == U256::from(10)
1425        ));
1426        assert!(matches!(
1427            HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1428            Ok(Some(v)) if v == U256::from(10)
1429        ));
1430        assert!(matches!(
1431            HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1432            Ok(Some(v)) if v == U256::from(15)
1433        ));
1434        assert!(matches!(
1435            HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1436            Ok(Some(v)) if v == U256::from(100)
1437        ));
1438        assert!(matches!(
1439            HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1440                .storage(HIGHER_ADDRESS, STORAGE),
1441            Ok(None)
1442        ));
1443        assert!(matches!(
1444            HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1445            Ok(Some(v)) if v == U256::from(1000)
1446        ));
1447    }
1448
1449    #[test]
1450    fn test_needs_prev_shard_check() {
1451        // Only needs check when rank == 0 and found_block != block_number
1452        assert!(needs_prev_shard_check(0, Some(10), 5));
1453        assert!(needs_prev_shard_check(0, None, 5));
1454        assert!(!needs_prev_shard_check(0, Some(5), 5)); // found_block == block_number
1455        assert!(!needs_prev_shard_check(1, Some(10), 5)); // rank > 0
1456    }
1457}