Skip to main content

reth_provider/providers/
blockchain_provider.rs

1use crate::{
2    providers::{
3        ConsistentProvider, OverlayStateProvider, OverlayStateProviderFactory, ProviderNodeTypes,
4        RocksDBProvider, StaticFileProvider, StaticFileProviderRWRefMut,
5    },
6    AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
7    BlockReader, BlockReaderIdExt, BlockSource, CanonChainTracker, CanonStateNotifications,
8    CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader,
9    DatabaseProviderFactory, HashedPostStateProvider, HeaderProvider, ProviderError,
10    ProviderFactory, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt,
11    RocksDBProviderFactory, StageCheckpointReader, StateProviderBox, StateProviderFactory,
12    StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider,
13};
14use alloy_consensus::{transaction::TransactionMeta, BlockHeader};
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
16use alloy_primitives::{Address, BlockHash, BlockNumber, Bytes, TxHash, TxNumber, B256};
17use alloy_rpc_types_engine::ForkchoiceState;
18use reth_chain_state::{
19    BlockState, CanonicalInMemoryState, ForkChoiceNotifications, ForkChoiceSubscriptions,
20    MemoryOverlayStateProvider, PersistedBlockNotifications, PersistedBlockSubscriptions,
21};
22use reth_chainspec::ChainInfo;
23use reth_db_api::models::{AccountBeforeTx, BlockNumberAddress, StoredBlockBodyIndices};
24use reth_execution_types::ExecutionOutcome;
25use reth_node_types::{BlockTy, HeaderTy, NodeTypesWithDB, ReceiptTy, TxTy};
26use reth_primitives_traits::{
27    Account, RecoveredBlock, SealedHeader, SealedOrRecoveredBlock, StorageEntry,
28};
29use reth_prune_types::{PruneCheckpoint, PruneSegment};
30use reth_stages_types::{StageCheckpoint, StageId};
31use reth_static_file_types::StaticFileSegment;
32use reth_storage_api::{
33    BlockBodyIndicesProvider, NodePrimitivesProvider, RangeEnd, RangeResponse, RangeResult,
34    StateRangeProvider, StateRangeProviderFactory, StateRangeView, StorageChangeSetReader,
35    StorageRangeResult,
36};
37use reth_storage_errors::provider::ProviderResult;
38use reth_trie::{
39    hashed_cursor::{HashedCursor, HashedCursorFactory},
40    metrics::TrieRootMetrics,
41    proof::{Proof, StorageProof},
42    HashedPostState, KeccakKeyHasher, MultiProofTargets, StorageRoot, TrieInput, TrieInputSorted,
43    TrieType,
44};
45use revm::database::BundleState;
46use std::{
47    ops::{RangeBounds, RangeInclusive},
48    sync::Arc,
49    time::Instant,
50};
51use tracing::trace;
52
53/// Number of most-recent blocks whose state roots remain resolvable via
54/// [`StateRangeProviderFactory::state_range_provider`].
55pub const SNAPSHOT_STATE_RETENTION: u64 = 128;
56
57type StateRangeDbProvider<N> = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
58type HistoricalStateRangeProvider<N> = OverlayStateProvider<StateRangeDbProvider<N>>;
59
60/// The main type for interacting with the blockchain.
61///
62/// This type serves as the main entry point for interacting with the blockchain and provides data
63/// from database storage and from the blockchain tree (pending state etc.) It is a simple wrapper
64/// type that holds an instance of the database and the blockchain tree.
65#[derive(Debug)]
66pub struct BlockchainProvider<N: NodeTypesWithDB> {
67    /// Provider factory used to access the database.
68    pub(crate) database: ProviderFactory<N>,
69    /// Tracks the chain info wrt forkchoice updates and in memory canonical
70    /// state.
71    pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
72    /// Store for BALs associated with this provider view.
73    pub(crate) bal_store: BalStoreHandle,
74}
75
76impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
77    fn clone(&self) -> Self {
78        Self {
79            database: self.database.clone(),
80            canonical_in_memory_state: self.canonical_in_memory_state.clone(),
81            bal_store: self.bal_store.clone(),
82        }
83    }
84}
85
86impl<N: ProviderNodeTypes> BlockchainProvider<N> {
87    /// Create a new [`BlockchainProvider`] using only the storage, fetching the latest
88    /// header from the database to initialize the provider.
89    pub fn new(storage: ProviderFactory<N>) -> ProviderResult<Self> {
90        let provider = storage.provider()?;
91        let best = provider.chain_info()?;
92        match provider.header_by_number(best.best_number)? {
93            Some(header) => {
94                drop(provider);
95                Ok(Self::with_latest(storage, SealedHeader::new(header, best.best_hash))?)
96            }
97            None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
98        }
99    }
100
101    /// Create new provider instance that wraps the database and the blockchain tree, using the
102    /// provided latest header to initialize the chain info tracker.
103    ///
104    /// This returns a `ProviderResult` since it tries the retrieve the last finalized header from
105    /// `database`.
106    pub fn with_latest(
107        storage: ProviderFactory<N>,
108        latest: SealedHeader<HeaderTy<N>>,
109    ) -> ProviderResult<Self> {
110        let provider = storage.provider()?;
111        let finalized_header = provider
112            .last_finalized_block_number()?
113            .map(|num| provider.sealed_header(num))
114            .transpose()?
115            .flatten();
116        let safe_header = provider
117            .last_safe_block_number()?
118            .or_else(|| {
119                // for the purpose of this we can also use the finalized block if we don't have the
120                // safe block
121                provider.last_finalized_block_number().ok().flatten()
122            })
123            .map(|num| provider.sealed_header(num))
124            .transpose()?
125            .flatten();
126        let bal_store = storage.bal_store().clone();
127
128        Ok(Self {
129            database: storage,
130            canonical_in_memory_state: CanonicalInMemoryState::with_head(
131                latest,
132                finalized_header,
133                safe_header,
134            ),
135            bal_store,
136        })
137    }
138
139    /// Gets a clone of `canonical_in_memory_state`.
140    pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
141        self.canonical_in_memory_state.clone()
142    }
143
144    /// Returns a provider with a created `DbTx` inside, which allows fetching data from the
145    /// database using different types of providers. Example: [`HeaderProvider`]
146    /// [`BlockHashReader`]. This may fail if the inner read database transaction fails to open.
147    #[track_caller]
148    pub fn consistent_provider(&self) -> ProviderResult<ConsistentProvider<N>> {
149        ConsistentProvider::new(self.database.clone(), self.canonical_in_memory_state())
150    }
151
152    /// This uses a given [`BlockState`] to initialize a state provider for that block.
153    fn block_state_provider(
154        &self,
155        state: &BlockState<N::Primitives>,
156    ) -> ProviderResult<MemoryOverlayStateProvider<N::Primitives>> {
157        let anchor_hash = state.anchor().hash;
158        let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
159        Ok(state.state_provider(latest_historical))
160    }
161
162    /// Returns a cursor-backed state view for a state root still only in canonical in-memory
163    /// blocks, overlaying their merged trie state on the persisted anchor.
164    fn block_state_range_provider(
165        &self,
166        state_root: B256,
167    ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
168        let Some(matched) = self
169            .canonical_in_memory_state
170            .canonical_chain()
171            .find(|state| state.state_root() == state_root)
172        else {
173            return Ok(None)
174        };
175
176        // Merge each in-memory block's trie delta, anchor to `matched`, oldest to newest.
177        let blocks: Vec<_> = matched.chain().map(|state| state.block()).collect();
178        let sorted: Vec<_> =
179            blocks.iter().rev().map(|block| (block.hashed_state(), block.trie_updates())).collect();
180        let input = TrieInput::from_blocks_sorted(
181            sorted.iter().map(|(state, nodes)| (state.as_ref(), nodes.as_ref())),
182        );
183        let merged = TrieInputSorted::from_unsorted(input);
184
185        // Anchor at the persisted block; the overlay reverts any db-tip advancement past it
186        // via changesets, then the merged in-memory delta applies on top.
187        let overlay_factory = OverlayStateProviderFactory::new(
188            self.database.clone(),
189            self.database
190                .overlay_manager()
191                .overlay_builder(matched.anchor().hash)
192                .with_immediate_state_trie_overlay(merged.state, merged.nodes),
193        );
194        reth_storage_api::DatabaseProviderROFactory::database_provider_ro(&overlay_factory)
195            .map(Some)
196    }
197
198    /// Returns a cursor-backed state view for a retained canonical state root.
199    fn historical_state_range_provider(
200        &self,
201        state_root: B256,
202    ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
203        let provider = self.database.provider()?;
204        let Some(finish) = provider.get_stage_checkpoint(StageId::Finish)? else { return Ok(None) };
205        let oldest = finish.block_number.saturating_sub(SNAPSHOT_STATE_RETENTION - 1);
206        let mut block_hash = None;
207
208        for number in (oldest..=finish.block_number).rev() {
209            let Some(header) = provider.sealed_header(number)? else { continue };
210            if header.state_root() == state_root {
211                block_hash = Some(header.hash());
212                break
213            }
214        }
215        drop(provider);
216
217        let Some(block_hash) = block_hash else { return Ok(None) };
218        let overlay_factory = OverlayStateProviderFactory::new(
219            self.database.clone(),
220            self.database.overlay_manager().overlay_builder(block_hash),
221        );
222        reth_storage_api::DatabaseProviderROFactory::database_provider_ro(&overlay_factory)
223            .map(Some)
224    }
225}
226
227impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
228    type Primitives = N::Primitives;
229}
230
231impl<N: NodeTypesWithDB> BalProvider for BlockchainProvider<N> {
232    fn bal_store(&self) -> &BalStoreHandle {
233        &self.bal_store
234    }
235}
236
237/// State range view backed by one resolved historical overlay.
238struct HistoricalStateRangeView<N: ProviderNodeTypes> {
239    provider: HistoricalStateRangeProvider<N>,
240}
241
242impl<N: ProviderNodeTypes> StateRangeProviderFactory for BlockchainProvider<N> {
243    /// Resolves a retained canonical state root into a pinned range view, preferring a still
244    /// in-memory block over the persisted-history fallback.
245    fn state_range_provider(&self, state_root: B256) -> ProviderResult<Option<StateRangeView>> {
246        let provider = match self.block_state_range_provider(state_root)? {
247            Some(provider) => Some(provider),
248            None => self.historical_state_range_provider(state_root)?,
249        };
250        Ok(provider
251            .map(|provider| Box::new(HistoricalStateRangeView { provider }) as StateRangeView))
252    }
253}
254
255impl<N: ProviderNodeTypes> StateRangeProvider for HistoricalStateRangeView<N> {
256    fn account_range(
257        &self,
258        start: B256,
259        limit: B256,
260        response_bytes: usize,
261    ) -> RangeResult<(B256, Account)> {
262        let mut cursor = self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
263
264        let mut accounts = Vec::new();
265        let mut total_bytes = 0usize;
266        let mut end = RangeEnd::Exhausted;
267
268        // Append before checking `limit`, so an empty `[start, limit]` still returns the account
269        // right past `limit`, provable as an empty range rather than a skipped one.
270        let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
271        while let Some((hash, account)) = entry {
272            total_bytes += 32 + 4 * 32; // hash + rough upper bound of the RLP account body
273            accounts.push((hash, account));
274            if hash >= limit {
275                end = RangeEnd::HashLimit;
276                break
277            }
278            if total_bytes > response_bytes {
279                end = RangeEnd::ByteLimit;
280                break
281            }
282            entry = cursor.next().map_err(ProviderError::Database)?;
283        }
284
285        Ok(RangeResponse { items: accounts, end })
286    }
287
288    fn storage_root_by_hash(&self, hashed_address: B256) -> ProviderResult<B256> {
289        let root = StorageRoot::new_hashed(
290            &self.provider,
291            &self.provider,
292            hashed_address,
293            Default::default(),
294            TrieRootMetrics::new(TrieType::Storage),
295        )
296        .root()
297        .map_err(|err| ProviderError::Database(err.into()))?;
298        Ok(root)
299    }
300
301    fn storage_range(
302        &self,
303        hashed_address: B256,
304        start: B256,
305        limit: B256,
306        response_bytes: usize,
307    ) -> StorageRangeResult {
308        // Distinguish an absent account from one with no storage, so callers don't silently
309        // omit it and shift later accounts' positions.
310        let mut account_cursor =
311            self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
312        let found = account_cursor.seek(hashed_address).map_err(ProviderError::Database)?;
313        if found.map(|(hash, _)| hash) != Some(hashed_address) {
314            return Ok(None)
315        }
316
317        let mut cursor =
318            self.provider.hashed_storage_cursor(hashed_address).map_err(ProviderError::Database)?;
319
320        let mut slots = Vec::new();
321        let mut total_bytes = 0usize;
322        let mut end = RangeEnd::Exhausted;
323
324        // Append before checking `limit`, so an empty `[start, limit]` still returns the slot
325        // right past `limit`, provable as an empty range rather than a skipped one.
326        let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
327        while let Some((hash, value)) = entry {
328            total_bytes += 64;
329            slots.push((hash, value));
330            if hash >= limit {
331                end = RangeEnd::HashLimit;
332                break
333            }
334            if total_bytes > response_bytes {
335                end = RangeEnd::ByteLimit;
336                break
337            }
338            entry = cursor.next().map_err(ProviderError::Database)?;
339        }
340
341        Ok(Some(RangeResponse { items: slots, end }))
342    }
343
344    fn account_range_proof(&self, keys: &[B256]) -> ProviderResult<Vec<Bytes>> {
345        let multiproof = Proof::new(&self.provider, &self.provider)
346            .multiproof(MultiProofTargets::accounts(keys.iter().copied()))
347            .map_err(ProviderError::from)?;
348        Ok(multiproof
349            .account_subtree
350            .into_nodes_sorted()
351            .into_iter()
352            .map(|(_, bytes)| bytes)
353            .collect())
354    }
355
356    fn storage_range_proof(
357        &self,
358        hashed_address: B256,
359        keys: &[B256],
360    ) -> ProviderResult<Vec<Bytes>> {
361        let multiproof = StorageProof::new_hashed(&self.provider, &self.provider, hashed_address)
362            .storage_multiproof(keys.iter().copied().collect())
363            .map_err(ProviderError::from)?;
364        Ok(multiproof.subtree.into_nodes_sorted().into_iter().map(|(_, bytes)| bytes).collect())
365    }
366}
367
368impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
369    type DB = N::DB;
370    type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
371    type ProviderRW = <ProviderFactory<N> as DatabaseProviderFactory>::ProviderRW;
372
373    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
374        DatabaseProviderFactory::database_provider_ro(&self.database)
375    }
376
377    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
378        DatabaseProviderFactory::database_provider_rw(&self.database)
379    }
380}
381
382impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
383    fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
384        self.database.static_file_provider()
385    }
386
387    fn get_static_file_writer(
388        &self,
389        block: BlockNumber,
390        segment: StaticFileSegment,
391    ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
392        self.database.get_static_file_writer(block, segment)
393    }
394}
395
396impl<N: ProviderNodeTypes> RocksDBProviderFactory for BlockchainProvider<N> {
397    fn rocksdb_provider(&self) -> RocksDBProvider {
398        self.database.rocksdb_provider()
399    }
400
401    fn set_pending_rocksdb_batch(&self, _batch: rocksdb::WriteBatchWithTransaction<true>) {
402        unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::set_pending_rocksdb_batch instead")
403    }
404
405    fn commit_pending_rocksdb_batches(&self) -> ProviderResult<()> {
406        unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::commit_pending_rocksdb_batches instead")
407    }
408}
409
410impl<N: ProviderNodeTypes> HeaderProvider for BlockchainProvider<N> {
411    type Header = HeaderTy<N>;
412
413    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
414        self.consistent_provider()?.header(block_hash)
415    }
416
417    fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
418        self.consistent_provider()?.header_by_number(num)
419    }
420
421    fn headers_range(
422        &self,
423        range: impl RangeBounds<BlockNumber>,
424    ) -> ProviderResult<Vec<Self::Header>> {
425        self.consistent_provider()?.headers_range(range)
426    }
427
428    fn sealed_header(
429        &self,
430        number: BlockNumber,
431    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
432        self.consistent_provider()?.sealed_header(number)
433    }
434
435    fn sealed_headers_range(
436        &self,
437        range: impl RangeBounds<BlockNumber>,
438    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
439        self.consistent_provider()?.sealed_headers_range(range)
440    }
441
442    fn sealed_headers_while(
443        &self,
444        range: impl RangeBounds<BlockNumber>,
445        predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
446    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
447        self.consistent_provider()?.sealed_headers_while(range, predicate)
448    }
449}
450
451impl<N: ProviderNodeTypes> BlockHashReader for BlockchainProvider<N> {
452    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
453        self.consistent_provider()?.block_hash(number)
454    }
455
456    fn canonical_hashes_range(
457        &self,
458        start: BlockNumber,
459        end: BlockNumber,
460    ) -> ProviderResult<Vec<B256>> {
461        self.consistent_provider()?.canonical_hashes_range(start, end)
462    }
463}
464
465impl<N: ProviderNodeTypes> BlockNumReader for BlockchainProvider<N> {
466    fn chain_info(&self) -> ProviderResult<ChainInfo> {
467        Ok(self.canonical_in_memory_state.chain_info())
468    }
469
470    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
471        Ok(self.canonical_in_memory_state.get_canonical_block_number())
472    }
473
474    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
475        self.database.last_block_number()
476    }
477
478    fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
479        self.database.earliest_block_number()
480    }
481
482    fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
483        self.consistent_provider()?.block_number(hash)
484    }
485}
486
487impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
488    fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
489        Ok(self.canonical_in_memory_state.pending_block_num_hash())
490    }
491
492    fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
493        Ok(self.canonical_in_memory_state.get_safe_num_hash())
494    }
495
496    fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
497        Ok(self.canonical_in_memory_state.get_finalized_num_hash())
498    }
499}
500
501impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
502    type Block = BlockTy<N>;
503
504    fn find_block_by_hash(
505        &self,
506        hash: B256,
507        source: BlockSource,
508    ) -> ProviderResult<Option<Self::Block>> {
509        self.consistent_provider()?.find_block_by_hash(hash, source)
510    }
511
512    fn find_sealed_or_recovered_block(
513        &self,
514        hash: B256,
515        source: BlockSource,
516    ) -> ProviderResult<Option<SealedOrRecoveredBlock<Self::Block>>> {
517        self.consistent_provider()?.find_sealed_or_recovered_block(hash, source)
518    }
519
520    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
521        self.consistent_provider()?.block(id)
522    }
523
524    fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
525        Ok(self.canonical_in_memory_state.pending_recovered_block())
526    }
527
528    fn pending_block_and_receipts(
529        &self,
530    ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
531        Ok(self.canonical_in_memory_state.pending_block_and_receipts())
532    }
533
534    /// Returns the block with senders with matching number or hash from database.
535    ///
536    /// **NOTE: If [`TransactionVariant::NoHash`] is provided then the transactions have invalid
537    /// hashes, since they would need to be calculated on the spot, and we want fast querying.**
538    ///
539    /// Returns `None` if block is not found.
540    fn recovered_block(
541        &self,
542        id: BlockHashOrNumber,
543        transaction_kind: TransactionVariant,
544    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
545        self.consistent_provider()?.recovered_block(id, transaction_kind)
546    }
547
548    fn sealed_block_with_senders(
549        &self,
550        id: BlockHashOrNumber,
551        transaction_kind: TransactionVariant,
552    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
553        self.consistent_provider()?.sealed_block_with_senders(id, transaction_kind)
554    }
555
556    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
557        self.consistent_provider()?.block_range(range)
558    }
559
560    fn block_with_senders_range(
561        &self,
562        range: RangeInclusive<BlockNumber>,
563    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
564        self.consistent_provider()?.block_with_senders_range(range)
565    }
566
567    fn recovered_block_range(
568        &self,
569        range: RangeInclusive<BlockNumber>,
570    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
571        self.consistent_provider()?.recovered_block_range(range)
572    }
573
574    fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
575        self.consistent_provider()?.block_by_transaction_id(id)
576    }
577}
578
579impl<N: ProviderNodeTypes> TransactionsProvider for BlockchainProvider<N> {
580    type Transaction = TxTy<N>;
581
582    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
583        self.consistent_provider()?.transaction_id(tx_hash)
584    }
585
586    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
587        self.consistent_provider()?.transaction_by_id(id)
588    }
589
590    fn transaction_by_id_unhashed(
591        &self,
592        id: TxNumber,
593    ) -> ProviderResult<Option<Self::Transaction>> {
594        self.consistent_provider()?.transaction_by_id_unhashed(id)
595    }
596
597    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
598        self.consistent_provider()?.transaction_by_hash(hash)
599    }
600
601    fn transaction_by_hash_with_meta(
602        &self,
603        tx_hash: TxHash,
604    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
605        self.consistent_provider()?.transaction_by_hash_with_meta(tx_hash)
606    }
607
608    fn transactions_by_block(
609        &self,
610        id: BlockHashOrNumber,
611    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
612        self.consistent_provider()?.transactions_by_block(id)
613    }
614
615    fn transactions_by_block_range(
616        &self,
617        range: impl RangeBounds<BlockNumber>,
618    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
619        self.consistent_provider()?.transactions_by_block_range(range)
620    }
621
622    fn transactions_by_tx_range(
623        &self,
624        range: impl RangeBounds<TxNumber>,
625    ) -> ProviderResult<Vec<Self::Transaction>> {
626        self.consistent_provider()?.transactions_by_tx_range(range)
627    }
628
629    fn senders_by_tx_range(
630        &self,
631        range: impl RangeBounds<TxNumber>,
632    ) -> ProviderResult<Vec<Address>> {
633        self.consistent_provider()?.senders_by_tx_range(range)
634    }
635
636    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
637        self.consistent_provider()?.transaction_sender(id)
638    }
639}
640
641impl<N: ProviderNodeTypes> ReceiptProvider for BlockchainProvider<N> {
642    type Receipt = ReceiptTy<N>;
643
644    fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
645        self.consistent_provider()?.receipt(id)
646    }
647
648    fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
649        self.consistent_provider()?.receipt_by_hash(hash)
650    }
651
652    fn receipts_by_block(
653        &self,
654        block: BlockHashOrNumber,
655    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
656        self.consistent_provider()?.receipts_by_block(block)
657    }
658
659    fn receipts_by_tx_range(
660        &self,
661        range: impl RangeBounds<TxNumber>,
662    ) -> ProviderResult<Vec<Self::Receipt>> {
663        self.consistent_provider()?.receipts_by_tx_range(range)
664    }
665
666    fn receipts_by_block_range(
667        &self,
668        block_range: RangeInclusive<BlockNumber>,
669    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
670        self.consistent_provider()?.receipts_by_block_range(block_range)
671    }
672}
673
674impl<N: ProviderNodeTypes> ReceiptProviderIdExt for BlockchainProvider<N> {
675    fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
676        self.consistent_provider()?.receipts_by_block_id(block)
677    }
678}
679
680impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for BlockchainProvider<N> {
681    fn block_body_indices(
682        &self,
683        number: BlockNumber,
684    ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
685        self.consistent_provider()?.block_body_indices(number)
686    }
687
688    fn block_body_indices_range(
689        &self,
690        range: RangeInclusive<BlockNumber>,
691    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
692        self.consistent_provider()?.block_body_indices_range(range)
693    }
694}
695
696impl<N: ProviderNodeTypes> StageCheckpointReader for BlockchainProvider<N> {
697    fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
698        self.consistent_provider()?.get_stage_checkpoint(id)
699    }
700
701    fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
702        self.consistent_provider()?.get_stage_checkpoint_progress(id)
703    }
704
705    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
706        self.consistent_provider()?.get_all_checkpoints()
707    }
708}
709
710impl<N: ProviderNodeTypes> PruneCheckpointReader for BlockchainProvider<N> {
711    fn get_prune_checkpoint(
712        &self,
713        segment: PruneSegment,
714    ) -> ProviderResult<Option<PruneCheckpoint>> {
715        self.consistent_provider()?.get_prune_checkpoint(segment)
716    }
717
718    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
719        self.consistent_provider()?.get_prune_checkpoints()
720    }
721}
722
723impl<N: NodeTypesWithDB> ChainSpecProvider for BlockchainProvider<N> {
724    type ChainSpec = N::ChainSpec;
725
726    fn chain_spec(&self) -> Arc<N::ChainSpec> {
727        self.database.chain_spec()
728    }
729}
730
731impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider<N> {
732    /// Storage provider for latest block
733    fn latest(&self) -> ProviderResult<StateProviderBox> {
734        trace!(target: "providers::blockchain", "Getting latest block state provider");
735        // use latest state provider if the head state exists
736        if let Some(state) = self.canonical_in_memory_state.head_state() {
737            trace!(target: "providers::blockchain", "Using head state for latest state provider");
738            Ok(self.block_state_provider(&state)?.boxed())
739        } else {
740            trace!(target: "providers::blockchain", "Using database state for latest state provider");
741            self.database.latest()
742        }
743    }
744
745    /// Returns a [`StateProviderBox`] indexed by the given block number or tag.
746    fn state_by_block_number_or_tag(
747        &self,
748        number_or_tag: BlockNumberOrTag,
749    ) -> ProviderResult<StateProviderBox> {
750        match number_or_tag {
751            BlockNumberOrTag::Latest => self.latest(),
752            BlockNumberOrTag::Finalized => {
753                // we can only get the finalized state by hash, not by num
754                let hash =
755                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
756                self.state_by_block_hash(hash)
757            }
758            BlockNumberOrTag::Safe => {
759                // we can only get the safe state by hash, not by num
760                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
761                self.state_by_block_hash(hash)
762            }
763            BlockNumberOrTag::Earliest => {
764                self.history_by_block_number(self.earliest_block_number()?)
765            }
766            BlockNumberOrTag::Pending => self.pending(),
767            BlockNumberOrTag::Number(num) => {
768                let hash = self
769                    .block_hash(num)?
770                    .ok_or_else(|| ProviderError::HeaderNotFound(num.into()))?;
771                self.state_by_block_hash(hash)
772            }
773        }
774    }
775
776    fn history_by_block_number(
777        &self,
778        block_number: BlockNumber,
779    ) -> ProviderResult<StateProviderBox> {
780        trace!(target: "providers::blockchain", ?block_number, "Getting history by block number");
781        let provider = self.consistent_provider()?;
782        let hash = provider
783            .block_hash(block_number)?
784            .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
785        provider.into_state_provider_at_block_hash(hash)
786    }
787
788    fn history_by_block_hash(&self, block_hash: BlockHash) -> ProviderResult<StateProviderBox> {
789        trace!(target: "providers::blockchain", ?block_hash, "Getting history by block hash");
790        self.consistent_provider()?.into_state_provider_at_block_hash(block_hash)
791    }
792
793    fn state_by_block_hash(&self, hash: BlockHash) -> ProviderResult<StateProviderBox> {
794        trace!(target: "providers::blockchain", ?hash, "Getting state by block hash");
795        if let Ok(state) = self.history_by_block_hash(hash) {
796            // This could be tracked by a historical block
797            Ok(state)
798        } else if let Ok(Some(pending)) = self.pending_state_by_hash(hash) {
799            // .. or this could be the pending state
800            Ok(pending)
801        } else {
802            // if we couldn't find it anywhere, then we should return an error
803            Err(ProviderError::StateForHashNotFound(hash))
804        }
805    }
806
807    /// Returns the state provider for pending state.
808    ///
809    /// If there's no pending block available then the latest state provider is returned:
810    /// [`Self::latest`]
811    fn pending(&self) -> ProviderResult<StateProviderBox> {
812        trace!(target: "providers::blockchain", "Getting provider for pending state");
813
814        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
815            // we have a pending block
816            return Ok(Box::new(self.block_state_provider(&pending)?));
817        }
818
819        // fallback to latest state if the pending block is not available
820        self.latest()
821    }
822
823    fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
824        if let Some(pending) = self.canonical_in_memory_state.pending_state() &&
825            pending.hash() == block_hash
826        {
827            return Ok(Some(Box::new(self.block_state_provider(&pending)?)));
828        }
829        Ok(None)
830    }
831
832    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
833        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
834            return Ok(Some(Box::new(self.block_state_provider(&pending)?)))
835        }
836
837        Ok(None)
838    }
839}
840
841impl<N: NodeTypesWithDB> HashedPostStateProvider for BlockchainProvider<N> {
842    fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState {
843        HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
844    }
845}
846
847impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider<N> {
848    type Header = HeaderTy<N>;
849
850    fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
851        // update timestamp
852        self.canonical_in_memory_state.on_forkchoice_update_received();
853    }
854
855    fn last_received_update_timestamp(&self) -> Option<Instant> {
856        self.canonical_in_memory_state.last_received_update_timestamp()
857    }
858
859    fn set_canonical_head(&self, header: SealedHeader<Self::Header>) {
860        self.canonical_in_memory_state.set_canonical_head(header);
861    }
862
863    fn set_safe(&self, header: SealedHeader<Self::Header>) {
864        self.canonical_in_memory_state.set_safe(header);
865    }
866
867    fn set_finalized(&self, header: SealedHeader<Self::Header>) {
868        self.canonical_in_memory_state.set_finalized(header);
869    }
870}
871
872impl<N: ProviderNodeTypes> BlockReaderIdExt for BlockchainProvider<N>
873where
874    Self: ReceiptProviderIdExt,
875{
876    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
877        self.consistent_provider()?.block_by_id(id)
878    }
879
880    fn header_by_number_or_tag(
881        &self,
882        id: BlockNumberOrTag,
883    ) -> ProviderResult<Option<Self::Header>> {
884        self.consistent_provider()?.header_by_number_or_tag(id)
885    }
886
887    fn sealed_header_by_number_or_tag(
888        &self,
889        id: BlockNumberOrTag,
890    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
891        self.consistent_provider()?.sealed_header_by_number_or_tag(id)
892    }
893
894    fn sealed_header_by_id(
895        &self,
896        id: BlockId,
897    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
898        self.consistent_provider()?.sealed_header_by_id(id)
899    }
900
901    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
902        self.consistent_provider()?.header_by_id(id)
903    }
904}
905
906impl<N: ProviderNodeTypes> CanonStateSubscriptions for BlockchainProvider<N> {
907    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<Self::Primitives> {
908        self.canonical_in_memory_state.subscribe_canon_state()
909    }
910}
911
912impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider<N> {
913    type Header = HeaderTy<N>;
914
915    fn subscribe_safe_block(&self) -> ForkChoiceNotifications<Self::Header> {
916        let receiver = self.canonical_in_memory_state.subscribe_safe_block();
917        ForkChoiceNotifications(receiver)
918    }
919
920    fn subscribe_finalized_block(&self) -> ForkChoiceNotifications<Self::Header> {
921        let receiver = self.canonical_in_memory_state.subscribe_finalized_block();
922        ForkChoiceNotifications(receiver)
923    }
924}
925
926impl<N: ProviderNodeTypes> PersistedBlockSubscriptions for BlockchainProvider<N> {
927    fn subscribe_persisted_block(&self) -> PersistedBlockNotifications {
928        let receiver = self.canonical_in_memory_state.subscribe_persisted_block();
929        PersistedBlockNotifications(receiver)
930    }
931}
932
933impl<N: ProviderNodeTypes> StorageChangeSetReader for BlockchainProvider<N> {
934    fn storage_changeset(
935        &self,
936        block_number: BlockNumber,
937    ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
938        self.consistent_provider()?.storage_changeset(block_number)
939    }
940
941    fn get_storage_before_block(
942        &self,
943        block_number: BlockNumber,
944        address: Address,
945        storage_key: B256,
946    ) -> ProviderResult<Option<StorageEntry>> {
947        self.consistent_provider()?.get_storage_before_block(block_number, address, storage_key)
948    }
949
950    fn storage_changesets_range(
951        &self,
952        range: impl RangeBounds<BlockNumber>,
953    ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
954        self.consistent_provider()?.storage_changesets_range(range)
955    }
956}
957
958impl<N: ProviderNodeTypes> ChangeSetReader for BlockchainProvider<N> {
959    fn account_block_changeset(
960        &self,
961        block_number: BlockNumber,
962    ) -> ProviderResult<Vec<AccountBeforeTx>> {
963        self.consistent_provider()?.account_block_changeset(block_number)
964    }
965
966    fn get_account_before_block(
967        &self,
968        block_number: BlockNumber,
969        address: Address,
970    ) -> ProviderResult<Option<AccountBeforeTx>> {
971        self.consistent_provider()?.get_account_before_block(block_number, address)
972    }
973
974    fn account_changesets_range(
975        &self,
976        range: impl core::ops::RangeBounds<BlockNumber>,
977    ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
978        self.consistent_provider()?.account_changesets_range(range)
979    }
980}
981
982impl<N: ProviderNodeTypes> AccountReader for BlockchainProvider<N> {
983    /// Get basic account information.
984    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
985        self.consistent_provider()?.basic_account(address)
986    }
987}
988
989impl<N: ProviderNodeTypes> StateReader for BlockchainProvider<N> {
990    type Receipt = ReceiptTy<N>;
991
992    /// Re-constructs the [`ExecutionOutcome`] from in-memory and database state, if necessary.
993    ///
994    /// If data for the block does not exist, this will return [`None`].
995    ///
996    /// NOTE: This cannot be called safely in a loop outside of the blockchain tree thread. This is
997    /// because the [`CanonicalInMemoryState`] could change during a reorg, causing results to be
998    /// inconsistent. Currently this can safely be called within the blockchain tree thread,
999    /// because the tree thread is responsible for modifying the [`CanonicalInMemoryState`] in the
1000    /// first place.
1001    fn get_state(
1002        &self,
1003        block: BlockNumber,
1004    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1005        self.consistent_provider()?.get_state(block)
1006    }
1007}
1008
1009#[cfg(test)]
1010mod tests {
1011    use super::SNAPSHOT_STATE_RETENTION;
1012    use crate::{
1013        providers::BlockchainProvider,
1014        test_utils::{
1015            create_test_provider_factory, create_test_provider_factory_with_chain_spec,
1016            MockNodeTypesWithDB,
1017        },
1018        BlockWriter, CanonChainTracker, ProviderFactory, SaveBlocksInput,
1019    };
1020    use alloy_consensus::constants::EMPTY_ROOT_HASH;
1021    use alloy_eips::{BlockHashOrNumber, BlockNumHash, BlockNumberOrTag};
1022    use alloy_primitives::{keccak256, Address, BlockNumber, TxNumber, B256, U256};
1023    use itertools::Itertools;
1024    use rand::Rng;
1025    use reth_chain_state::{
1026        test_utils::TestBlockBuilder, CanonStateNotification, CanonStateSubscriptions,
1027        CanonicalInMemoryState, ExecutedBlock, NewCanonicalChain,
1028    };
1029    use reth_chainspec::{ChainSpec, MAINNET};
1030    use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
1031    use reth_errors::ProviderError;
1032    use reth_ethereum_primitives::{Block, Receipt};
1033    use reth_execution_types::{
1034        BlockExecutionOutput, BlockExecutionResult, Chain, ExecutionOutcome,
1035    };
1036    use reth_primitives_traits::{
1037        Account, Block as _, RecoveredBlock, SealedBlock, SignerRecoverable, StorageEntry,
1038    };
1039    use reth_stages_types::{StageCheckpoint, StageId};
1040    use reth_storage_api::{
1041        BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader,
1042        BlockReaderIdExt, BlockSource, ChangeSetReader, DBProvider, DatabaseProviderFactory,
1043        HashingWriter, HeaderProvider, RangeEnd, ReceiptProvider, ReceiptProviderIdExt,
1044        StageCheckpointWriter, StateProviderFactory, StateRangeProvider, StateRangeProviderFactory,
1045        StateRootProvider, StateWriteConfig, StateWriter, StorageRootProvider, TransactionVariant,
1046        TransactionsProvider,
1047    };
1048    use reth_testing_utils::generators::{
1049        self, random_block, random_block_range, random_changeset_range, random_eoa_accounts,
1050        random_receipt, BlockParams, BlockRangeParams,
1051    };
1052    use reth_trie::{updates::TrieUpdates, ComputedTrieData, HashedPostState, HashedStorage};
1053    use revm::database::{BundleState, OriginalValuesKnown};
1054    use std::{
1055        collections::{BTreeMap, HashMap},
1056        ops::{Bound, Range, RangeBounds},
1057        sync::Arc,
1058    };
1059
1060    const TEST_BLOCKS_COUNT: usize = 5;
1061
1062    const TEST_TRANSACTIONS_COUNT: u8 = 4;
1063
1064    fn random_blocks(
1065        rng: &mut impl Rng,
1066        database_blocks: usize,
1067        in_memory_blocks: usize,
1068        requests_count: Option<Range<u8>>,
1069        withdrawals_count: Option<Range<u8>>,
1070        tx_count: impl RangeBounds<u8>,
1071    ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1072        let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1073
1074        let tx_start = match tx_count.start_bound() {
1075            Bound::Included(&n) | Bound::Excluded(&n) => n,
1076            Bound::Unbounded => u8::MIN,
1077        };
1078        let tx_end = match tx_count.end_bound() {
1079            Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1080            Bound::Unbounded => u8::MAX,
1081        };
1082
1083        let blocks = random_block_range(
1084            rng,
1085            0..=block_range,
1086            BlockRangeParams {
1087                parent: Some(B256::ZERO),
1088                tx_count: tx_start..tx_end,
1089                requests_count,
1090                withdrawals_count,
1091            },
1092        );
1093        let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1094        (database_blocks.to_vec(), in_memory_blocks.to_vec())
1095    }
1096
1097    #[expect(clippy::type_complexity)]
1098    fn provider_with_chain_spec_and_random_blocks(
1099        rng: &mut impl Rng,
1100        chain_spec: Arc<ChainSpec>,
1101        database_blocks: usize,
1102        in_memory_blocks: usize,
1103        block_range_params: BlockRangeParams,
1104    ) -> eyre::Result<(
1105        BlockchainProvider<MockNodeTypesWithDB>,
1106        Vec<SealedBlock<Block>>,
1107        Vec<SealedBlock<Block>>,
1108        Vec<Vec<Receipt>>,
1109    )> {
1110        let (database_blocks, in_memory_blocks) = random_blocks(
1111            rng,
1112            database_blocks,
1113            in_memory_blocks,
1114            block_range_params.requests_count,
1115            block_range_params.withdrawals_count,
1116            block_range_params.tx_count,
1117        );
1118
1119        let receipts: Vec<Vec<_>> = database_blocks
1120            .iter()
1121            .chain(in_memory_blocks.iter())
1122            .map(|block| block.body().transactions.iter())
1123            .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
1124            .collect();
1125
1126        let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1127        let provider_rw = factory.database_provider_rw()?;
1128
1129        // Insert blocks into the database
1130        for block in &database_blocks {
1131            provider_rw.insert_block(
1132                &block.clone().try_recover().expect("failed to seal block with senders"),
1133            )?;
1134        }
1135
1136        // Insert receipts into the database
1137        if let Some(first_block) = database_blocks.first() {
1138            provider_rw.write_state(
1139                &ExecutionOutcome {
1140                    first_block: first_block.number,
1141                    receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
1142                    ..Default::default()
1143                },
1144                OriginalValuesKnown::No,
1145                StateWriteConfig::default(),
1146            )?;
1147        }
1148
1149        provider_rw.commit()?;
1150
1151        let provider = BlockchainProvider::new(factory)?;
1152
1153        // Insert the rest of the blocks and receipts into the in-memory state
1154        let chain = NewCanonicalChain::Commit {
1155            new: in_memory_blocks
1156                .iter()
1157                .map(|block| {
1158                    let senders = block.senders().expect("failed to recover senders");
1159                    let block_receipts = receipts.get(block.number as usize).unwrap().clone();
1160                    let execution_outcome = BlockExecutionOutput {
1161                        result: BlockExecutionResult {
1162                            receipts: block_receipts,
1163                            requests: Default::default(),
1164                            gas_used: 0,
1165                            blob_gas_used: 0,
1166                        },
1167                        state: BundleState::default(),
1168                    };
1169
1170                    ExecutedBlock {
1171                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
1172                            block.clone(),
1173                            senders,
1174                        )),
1175                        execution_output: execution_outcome.into(),
1176                        ..Default::default()
1177                    }
1178                })
1179                .collect(),
1180        };
1181        provider.canonical_in_memory_state.update_chain(chain);
1182
1183        // Get canonical, safe, and finalized blocks
1184        let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
1185        let block_count = blocks.len();
1186        let canonical_block = blocks.get(block_count - 1).unwrap();
1187        let safe_block = blocks.get(block_count - 2).unwrap();
1188        let finalized_block = blocks.get(block_count - 3).unwrap();
1189
1190        // Set the canonical head, safe, and finalized blocks
1191        provider.set_canonical_head(canonical_block.clone_sealed_header());
1192        provider.set_safe(safe_block.clone_sealed_header());
1193        provider.set_finalized(finalized_block.clone_sealed_header());
1194
1195        Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
1196    }
1197
1198    #[expect(clippy::type_complexity)]
1199    fn provider_with_random_blocks(
1200        rng: &mut impl Rng,
1201        database_blocks: usize,
1202        in_memory_blocks: usize,
1203        block_range_params: BlockRangeParams,
1204    ) -> eyre::Result<(
1205        BlockchainProvider<MockNodeTypesWithDB>,
1206        Vec<SealedBlock<Block>>,
1207        Vec<SealedBlock<Block>>,
1208        Vec<Vec<Receipt>>,
1209    )> {
1210        provider_with_chain_spec_and_random_blocks(
1211            rng,
1212            MAINNET.clone(),
1213            database_blocks,
1214            in_memory_blocks,
1215            block_range_params,
1216        )
1217    }
1218
1219    /// This will persist the last block in-memory and delete it from
1220    /// `canonical_in_memory_state` right after a database read transaction is created.
1221    ///
1222    /// This simulates a RPC method having a different view than when its database transaction was
1223    /// created.
1224    fn persist_block_after_db_tx_creation(
1225        provider: BlockchainProvider<MockNodeTypesWithDB>,
1226        block_number: BlockNumber,
1227    ) {
1228        let hook_provider = provider.clone();
1229        provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
1230            if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
1231                state.anchor().number + 1 == block_number
1232            {
1233                let mut lowest_memory_block =
1234                    state.parent_state_chain().last().expect("qed").block();
1235                let num_hash = lowest_memory_block.recovered_block().num_hash();
1236
1237                let execution_output = (*lowest_memory_block.execution_output).clone();
1238                lowest_memory_block.execution_output = Arc::new(execution_output);
1239
1240                // Push to disk
1241                let provider_rw = hook_provider.database_provider_rw().unwrap();
1242                let input = SaveBlocksInput::new(
1243                    vec![lowest_memory_block],
1244                    state.anchor().number,
1245                    state.anchor().number,
1246                    block_number,
1247                    block_number,
1248                );
1249                provider_rw.save_blocks(&input).unwrap();
1250                provider_rw.commit().unwrap();
1251
1252                // Remove from memory
1253                hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
1254            }
1255        }));
1256    }
1257
1258    #[test]
1259    fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1260        // Initialize random number generator and provider factory
1261        let mut rng = generators::rng();
1262        let factory = create_test_provider_factory();
1263
1264        // Generate 10 random blocks and split into database and in-memory blocks
1265        let blocks = random_block_range(
1266            &mut rng,
1267            0..=10,
1268            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1269        );
1270        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1271
1272        // Insert first 5 blocks into the database
1273        let provider_rw = factory.provider_rw()?;
1274        for block in database_blocks {
1275            provider_rw.insert_block(
1276                &block.clone().try_recover().expect("failed to seal block with senders"),
1277            )?;
1278        }
1279
1280        provider_rw.commit()?;
1281
1282        // Create a new provider
1283        let provider = BlockchainProvider::new(factory)?;
1284
1285        // Useful blocks
1286        let first_db_block = database_blocks.first().unwrap();
1287        let first_in_mem_block = in_memory_blocks.first().unwrap();
1288        let last_in_mem_block = in_memory_blocks.last().unwrap();
1289
1290        // No block in memory before setting in memory state
1291        assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1292        assert_eq!(
1293            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1294            None
1295        );
1296        // No pending block in memory
1297        assert_eq!(
1298            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1299            None
1300        );
1301
1302        // Insert first block into the in-memory state
1303        let in_memory_block_senders =
1304            first_in_mem_block.senders().expect("failed to recover senders");
1305        let chain = NewCanonicalChain::Commit {
1306            new: vec![ExecutedBlock {
1307                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1308                    first_in_mem_block.clone(),
1309                    in_memory_block_senders,
1310                )),
1311                ..Default::default()
1312            }],
1313        };
1314        provider.canonical_in_memory_state.update_chain(chain);
1315
1316        // Now the block should be found in memory
1317        assert_eq!(
1318            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1319            Some(first_in_mem_block.clone().into_block())
1320        );
1321        assert_eq!(
1322            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1323            Some(first_in_mem_block.clone().into_block())
1324        );
1325
1326        // Find the first block in database by hash
1327        assert_eq!(
1328            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1329            Some(first_db_block.clone().into_block())
1330        );
1331        assert_eq!(
1332            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1333            Some(first_db_block.clone().into_block())
1334        );
1335
1336        // No pending block in database
1337        assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1338
1339        // Insert the last block into the pending state
1340        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1341            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1342                last_in_mem_block.clone(),
1343                Default::default(),
1344            )),
1345            ..Default::default()
1346        });
1347
1348        // Now the last block should be found in memory
1349        assert_eq!(
1350            provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1351            Some(last_in_mem_block.clone().into_block())
1352        );
1353
1354        Ok(())
1355    }
1356
1357    #[test]
1358    fn test_block_reader_block() -> eyre::Result<()> {
1359        // Initialize random number generator and provider factory
1360        let mut rng = generators::rng();
1361        let factory = create_test_provider_factory();
1362
1363        // Generate 10 random blocks and split into database and in-memory blocks
1364        let blocks = random_block_range(
1365            &mut rng,
1366            0..=10,
1367            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1368        );
1369        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1370
1371        // Insert first 5 blocks into the database
1372        let provider_rw = factory.provider_rw()?;
1373        for block in database_blocks {
1374            provider_rw.insert_block(
1375                &block.clone().try_recover().expect("failed to seal block with senders"),
1376            )?;
1377        }
1378        provider_rw.commit()?;
1379
1380        // Create a new provider
1381        let provider = BlockchainProvider::new(factory)?;
1382
1383        // First in memory block
1384        let first_in_mem_block = in_memory_blocks.first().unwrap();
1385        // First database block
1386        let first_db_block = database_blocks.first().unwrap();
1387
1388        // First in memory block should not be found yet as not integrated to the in-memory state
1389        assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1390        assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1391
1392        // Insert first block into the in-memory state
1393        let in_memory_block_senders =
1394            first_in_mem_block.senders().expect("failed to recover senders");
1395        let chain = NewCanonicalChain::Commit {
1396            new: vec![ExecutedBlock {
1397                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1398                    first_in_mem_block.clone(),
1399                    in_memory_block_senders,
1400                )),
1401                ..Default::default()
1402            }],
1403        };
1404        provider.canonical_in_memory_state.update_chain(chain);
1405
1406        // First in memory block should be found
1407        assert_eq!(
1408            provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1409            Some(first_in_mem_block.clone().into_block())
1410        );
1411        assert_eq!(
1412            provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1413            Some(first_in_mem_block.clone().into_block())
1414        );
1415
1416        // First database block should be found
1417        assert_eq!(
1418            provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1419            Some(first_db_block.clone().into_block())
1420        );
1421        assert_eq!(
1422            provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1423            Some(first_db_block.clone().into_block())
1424        );
1425
1426        Ok(())
1427    }
1428
1429    #[test]
1430    fn test_block_reader_pending_block() -> eyre::Result<()> {
1431        let mut rng = generators::rng();
1432        let (provider, _, _, _) = provider_with_random_blocks(
1433            &mut rng,
1434            TEST_BLOCKS_COUNT,
1435            TEST_BLOCKS_COUNT,
1436            BlockRangeParams::default(),
1437        )?;
1438
1439        // Generate a random block
1440        let mut rng = generators::rng();
1441        let block = random_block(
1442            &mut rng,
1443            0,
1444            BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1445        );
1446
1447        // Set the block as pending
1448        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1449            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1450                block.clone(),
1451                block.senders().unwrap(),
1452            )),
1453            ..Default::default()
1454        });
1455
1456        // Assertions related to the pending block
1457
1458        assert_eq!(
1459            provider.pending_block()?,
1460            Some(RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()))
1461        );
1462
1463        assert_eq!(
1464            provider.pending_block_and_receipts()?,
1465            Some((RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()), vec![]))
1466        );
1467
1468        Ok(())
1469    }
1470
1471    #[test]
1472    fn test_block_body_indices() -> eyre::Result<()> {
1473        // Create a new provider
1474        let mut rng = generators::rng();
1475        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1476            &mut rng,
1477            TEST_BLOCKS_COUNT,
1478            TEST_BLOCKS_COUNT,
1479            BlockRangeParams {
1480                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1481                ..Default::default()
1482            },
1483        )?;
1484
1485        let first_in_mem_block = in_memory_blocks.first().unwrap();
1486
1487        // Insert the first block into the in-memory state
1488        let in_memory_block_senders =
1489            first_in_mem_block.senders().expect("failed to recover senders");
1490        let chain = NewCanonicalChain::Commit {
1491            new: vec![ExecutedBlock {
1492                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1493                    first_in_mem_block.clone(),
1494                    in_memory_block_senders,
1495                )),
1496                ..Default::default()
1497            }],
1498        };
1499        provider.canonical_in_memory_state.update_chain(chain);
1500
1501        let first_db_block = database_blocks.first().unwrap().clone();
1502        let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1503
1504        // First database block body indices should be found
1505        assert_eq!(
1506            provider.block_body_indices(first_db_block.number)?.unwrap(),
1507            StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1508        );
1509
1510        // First in-memory block body indices should be found with the first tx after the database
1511        // blocks
1512        assert_eq!(
1513            provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1514            StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1515        );
1516
1517        // A random block number should return None as the block is not found
1518        let mut rng = rand::rng();
1519        let random_block_number: u64 = rng.random();
1520        assert_eq!(provider.block_body_indices(random_block_number)?, None);
1521
1522        Ok(())
1523    }
1524
1525    #[test]
1526    fn test_block_hash_reader() -> eyre::Result<()> {
1527        let mut rng = generators::rng();
1528        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1529            &mut rng,
1530            TEST_BLOCKS_COUNT,
1531            TEST_BLOCKS_COUNT,
1532            BlockRangeParams::default(),
1533        )?;
1534
1535        let database_block = database_blocks.first().unwrap().clone();
1536        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1537
1538        assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1539        assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1540
1541        assert_eq!(
1542            provider.canonical_hashes_range(0, 10)?,
1543            [database_blocks, in_memory_blocks]
1544                .concat()
1545                .iter()
1546                .map(|block| block.hash())
1547                .collect::<Vec<_>>()
1548        );
1549
1550        Ok(())
1551    }
1552
1553    #[test]
1554    fn test_header_provider() -> eyre::Result<()> {
1555        let mut rng = generators::rng();
1556        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1557            &mut rng,
1558            TEST_BLOCKS_COUNT,
1559            TEST_BLOCKS_COUNT,
1560            BlockRangeParams::default(),
1561        )?;
1562
1563        // make sure that the finalized block is on db
1564        let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1565        provider.set_finalized(finalized_block.clone_sealed_header());
1566
1567        let blocks = [database_blocks, in_memory_blocks].concat();
1568
1569        assert_eq!(
1570            provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1571            blocks
1572                .iter()
1573                .take_while(|header| header.number <= 8)
1574                .map(|b| b.clone_sealed_header())
1575                .collect::<Vec<_>>()
1576        );
1577
1578        Ok(())
1579    }
1580
1581    #[tokio::test]
1582    async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1583        let factory = create_test_provider_factory();
1584
1585        // Generate a random block to initialize the blockchain provider.
1586        let mut test_block_builder = TestBlockBuilder::eth();
1587        let block_1 = test_block_builder.generate_random_block(0, B256::ZERO).try_recover()?;
1588        let block_hash_1 = block_1.hash();
1589
1590        // Insert and commit the block.
1591        let provider_rw = factory.provider_rw()?;
1592        provider_rw.insert_block(&block_1)?;
1593        provider_rw.commit()?;
1594
1595        let provider = BlockchainProvider::new(factory)?;
1596
1597        // Subscribe twice for canonical state updates.
1598        let in_memory_state = provider.canonical_in_memory_state();
1599        let mut rx_1 = provider.subscribe_to_canonical_state();
1600        let mut rx_2 = provider.subscribe_to_canonical_state();
1601
1602        // Send and receive commit notifications.
1603        let block_2 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1604        let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), BTreeMap::new());
1605        let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1606        in_memory_state.notify_canon_state(commit.clone());
1607        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1608        assert_eq!(notification_1, Ok(commit.clone()));
1609        assert_eq!(notification_2, Ok(commit.clone()));
1610
1611        // Send and receive re-org notifications.
1612        let block_3 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1613        let block_4 = test_block_builder.generate_random_block(2, block_3.hash()).try_recover()?;
1614        let new_chain =
1615            Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), BTreeMap::new());
1616        let re_org =
1617            CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1618        in_memory_state.notify_canon_state(re_org.clone());
1619        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1620        assert_eq!(notification_1, Ok(re_org.clone()));
1621        assert_eq!(notification_2, Ok(re_org.clone()));
1622
1623        Ok(())
1624    }
1625
1626    #[test]
1627    fn test_block_num_reader() -> eyre::Result<()> {
1628        let mut rng = generators::rng();
1629        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1630            &mut rng,
1631            TEST_BLOCKS_COUNT,
1632            TEST_BLOCKS_COUNT,
1633            BlockRangeParams::default(),
1634        )?;
1635
1636        assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1637        assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1638
1639        let database_block = database_blocks.first().unwrap().clone();
1640        let in_memory_block = in_memory_blocks.first().unwrap().clone();
1641        assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1642        assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1643
1644        Ok(())
1645    }
1646
1647    #[test]
1648    fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1649        let mut rng = generators::rng();
1650        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1651            &mut rng,
1652            TEST_BLOCKS_COUNT,
1653            TEST_BLOCKS_COUNT,
1654            BlockRangeParams::default(),
1655        )?;
1656
1657        let database_block = database_blocks.first().unwrap().clone();
1658        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1659
1660        let block_number = database_block.number;
1661        let block_hash = database_block.hash();
1662
1663        assert_eq!(
1664            provider.block_by_id(block_number.into()).unwrap(),
1665            Some(database_block.clone().into_block())
1666        );
1667        assert_eq!(
1668            provider.block_by_id(block_hash.into()).unwrap(),
1669            Some(database_block.into_block())
1670        );
1671
1672        let block_number = in_memory_block.number;
1673        let block_hash = in_memory_block.hash();
1674        assert_eq!(
1675            provider.block_by_id(block_number.into()).unwrap(),
1676            Some(in_memory_block.clone().into_block())
1677        );
1678        assert_eq!(
1679            provider.block_by_id(block_hash.into()).unwrap(),
1680            Some(in_memory_block.into_block())
1681        );
1682
1683        Ok(())
1684    }
1685
1686    #[test]
1687    fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1688        let mut rng = generators::rng();
1689        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1690            &mut rng,
1691            TEST_BLOCKS_COUNT,
1692            TEST_BLOCKS_COUNT,
1693            BlockRangeParams::default(),
1694        )?;
1695
1696        let database_block = database_blocks.first().unwrap().clone();
1697
1698        let in_memory_block_count = in_memory_blocks.len();
1699        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1700        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1701        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1702
1703        let block_number = database_block.number;
1704        assert_eq!(
1705            provider.header_by_number_or_tag(block_number.into()).unwrap(),
1706            Some(database_block.header().clone())
1707        );
1708        assert_eq!(
1709            provider.sealed_header_by_number_or_tag(block_number.into())?,
1710            Some(database_block.clone_sealed_header())
1711        );
1712
1713        assert_eq!(
1714            provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1715            Some(canonical_block.header().clone())
1716        );
1717        assert_eq!(
1718            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1719            Some(canonical_block.clone_sealed_header())
1720        );
1721
1722        assert_eq!(
1723            provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1724            Some(safe_block.header().clone())
1725        );
1726        assert_eq!(
1727            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1728            Some(safe_block.clone_sealed_header())
1729        );
1730
1731        assert_eq!(
1732            provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1733            Some(finalized_block.header().clone())
1734        );
1735        assert_eq!(
1736            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1737            Some(finalized_block.clone_sealed_header())
1738        );
1739
1740        Ok(())
1741    }
1742
1743    #[test]
1744    fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1745        let mut rng = generators::rng();
1746        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1747            &mut rng,
1748            TEST_BLOCKS_COUNT,
1749            TEST_BLOCKS_COUNT,
1750            BlockRangeParams::default(),
1751        )?;
1752
1753        let database_block = database_blocks.first().unwrap().clone();
1754        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1755
1756        let block_number = database_block.number;
1757        let block_hash = database_block.hash();
1758
1759        assert_eq!(
1760            provider.header_by_id(block_number.into()).unwrap(),
1761            Some(database_block.header().clone())
1762        );
1763        assert_eq!(
1764            provider.sealed_header_by_id(block_number.into()).unwrap(),
1765            Some(database_block.clone_sealed_header())
1766        );
1767
1768        assert_eq!(
1769            provider.header_by_id(block_hash.into()).unwrap(),
1770            Some(database_block.header().clone())
1771        );
1772        assert_eq!(
1773            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1774            Some(database_block.clone_sealed_header())
1775        );
1776
1777        let block_number = in_memory_block.number;
1778        let block_hash = in_memory_block.hash();
1779
1780        assert_eq!(
1781            provider.header_by_id(block_number.into()).unwrap(),
1782            Some(in_memory_block.header().clone())
1783        );
1784        assert_eq!(
1785            provider.sealed_header_by_id(block_number.into()).unwrap(),
1786            Some(in_memory_block.clone_sealed_header())
1787        );
1788
1789        assert_eq!(
1790            provider.header_by_id(block_hash.into()).unwrap(),
1791            Some(in_memory_block.header().clone())
1792        );
1793        assert_eq!(
1794            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1795            Some(in_memory_block.clone_sealed_header())
1796        );
1797
1798        Ok(())
1799    }
1800
1801    #[test]
1802    fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
1803        let mut rng = generators::rng();
1804        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1805            &mut rng,
1806            TEST_BLOCKS_COUNT,
1807            TEST_BLOCKS_COUNT,
1808            BlockRangeParams { tx_count: 1..3, ..Default::default() },
1809        )?;
1810
1811        let database_block = database_blocks.first().unwrap().clone();
1812        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1813
1814        let block_number = database_block.number;
1815        let block_hash = database_block.hash();
1816
1817        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1818        assert!(!provider
1819            .receipts_by_number_or_tag(database_block.number.into())?
1820            .unwrap()
1821            .is_empty());
1822
1823        assert_eq!(
1824            provider.receipts_by_block_id(block_number.into())?.unwrap(),
1825            receipts.get(block_number as usize).unwrap().clone()
1826        );
1827        assert_eq!(
1828            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1829            receipts.get(block_number as usize).unwrap().clone()
1830        );
1831
1832        let block_number = in_memory_block.number;
1833        let block_hash = in_memory_block.hash();
1834
1835        assert_eq!(
1836            provider.receipts_by_block_id(block_number.into())?.unwrap(),
1837            receipts.get(block_number as usize).unwrap().clone()
1838        );
1839        assert_eq!(
1840            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1841            receipts.get(block_number as usize).unwrap().clone()
1842        );
1843
1844        Ok(())
1845    }
1846
1847    #[test]
1848    fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
1849        let mut rng = generators::rng();
1850        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1851            &mut rng,
1852            TEST_BLOCKS_COUNT,
1853            TEST_BLOCKS_COUNT,
1854            BlockRangeParams { tx_count: 1..3, ..Default::default() },
1855        )?;
1856
1857        let database_block = database_blocks.first().unwrap().clone();
1858
1859        let in_memory_block_count = in_memory_blocks.len();
1860        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1861        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1862        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1863
1864        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1865        assert!(!provider
1866            .receipts_by_number_or_tag(database_block.number.into())?
1867            .unwrap()
1868            .is_empty());
1869
1870        assert_eq!(
1871            provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
1872            receipts.get(database_block.number as usize).unwrap().clone()
1873        );
1874        assert_eq!(
1875            provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
1876            receipts.get(canonical_block.number as usize).unwrap().clone()
1877        );
1878        assert_eq!(
1879            provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
1880            receipts.get(safe_block.number as usize).unwrap().clone()
1881        );
1882        assert_eq!(
1883            provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
1884            receipts.get(finalized_block.number as usize).unwrap().clone()
1885        );
1886
1887        Ok(())
1888    }
1889
1890    #[test]
1891    fn test_changeset_reader() -> eyre::Result<()> {
1892        let mut rng = generators::rng();
1893
1894        let (database_blocks, in_memory_blocks) =
1895            random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1896
1897        let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1898        let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1899        let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1900
1901        let accounts = random_eoa_accounts(&mut rng, 2);
1902
1903        let (database_changesets, database_state) = random_changeset_range(
1904            &mut rng,
1905            &database_blocks,
1906            accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1907            0..0,
1908            0..0,
1909        );
1910        let (in_memory_changesets, in_memory_state) = random_changeset_range(
1911            &mut rng,
1912            &in_memory_blocks,
1913            database_state
1914                .iter()
1915                .map(|(address, (account, storage))| (*address, (*account, storage.clone()))),
1916            0..0,
1917            0..0,
1918        );
1919
1920        let factory = create_test_provider_factory();
1921
1922        let provider_rw = factory.provider_rw()?;
1923        provider_rw.append_blocks_with_state(
1924            database_blocks
1925                .into_iter()
1926                .map(|b| b.try_recover().expect("failed to seal block with senders"))
1927                .collect(),
1928            &ExecutionOutcome {
1929                bundle: BundleState::new(
1930                    database_state.into_iter().map(|(address, (account, _))| {
1931                        (address, None, Some(account.into()), Default::default())
1932                    }),
1933                    database_changesets.iter().map(|block_changesets| {
1934                        block_changesets.iter().map(|(address, account, _)| {
1935                            (*address, Some(Some((*account).into())), [])
1936                        })
1937                    }),
1938                    Vec::new(),
1939                ),
1940                first_block: first_database_block,
1941                ..Default::default()
1942            },
1943            Default::default(),
1944        )?;
1945        provider_rw.commit()?;
1946
1947        let provider = BlockchainProvider::new(factory)?;
1948
1949        let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1950        let chain = NewCanonicalChain::Commit {
1951            new: vec![in_memory_blocks
1952                .first()
1953                .map(|block| {
1954                    let senders = block.senders().expect("failed to recover senders");
1955                    ExecutedBlock {
1956                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
1957                            block.clone(),
1958                            senders,
1959                        )),
1960                        execution_output: Arc::new(BlockExecutionOutput {
1961                            state: BundleState::new(
1962                                in_memory_state.into_iter().map(|(address, (account, _))| {
1963                                    (address, None, Some(account.into()), Default::default())
1964                                }),
1965                                [in_memory_changesets.iter().map(|(address, account, _)| {
1966                                    (*address, Some(Some((*account).into())), Vec::new())
1967                                })],
1968                                [],
1969                            ),
1970                            result: BlockExecutionResult {
1971                                receipts: Default::default(),
1972                                requests: Default::default(),
1973                                gas_used: 0,
1974                                blob_gas_used: 0,
1975                            },
1976                        }),
1977                        ..Default::default()
1978                    }
1979                })
1980                .unwrap()],
1981        };
1982        provider.canonical_in_memory_state.update_chain(chain);
1983
1984        assert_eq!(
1985            provider.account_block_changeset(last_database_block).unwrap(),
1986            database_changesets
1987                .into_iter()
1988                .next_back()
1989                .unwrap()
1990                .into_iter()
1991                .sorted_by_key(|(address, _, _)| *address)
1992                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1993                .collect::<Vec<_>>()
1994        );
1995        assert_eq!(
1996            provider.account_block_changeset(first_in_memory_block).unwrap(),
1997            in_memory_changesets
1998                .into_iter()
1999                .sorted_by_key(|(address, _, _)| *address)
2000                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2001                .collect::<Vec<_>>()
2002        );
2003
2004        Ok(())
2005    }
2006
2007    #[test]
2008    fn test_state_provider_factory() -> eyre::Result<()> {
2009        let mut rng = generators::rng();
2010
2011        // test in-memory state use-cases
2012        let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2013            &mut rng,
2014            TEST_BLOCKS_COUNT,
2015            TEST_BLOCKS_COUNT,
2016            BlockRangeParams::default(),
2017        )?;
2018
2019        // test database state use-cases
2020        let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
2021            &mut rng,
2022            TEST_BLOCKS_COUNT,
2023            0,
2024            BlockRangeParams::default(),
2025        )?;
2026
2027        let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
2028        let first_in_memory_block = in_memory_blocks.first().unwrap();
2029        let first_db_block = database_blocks.first().unwrap();
2030
2031        // test latest state
2032        assert_eq!(
2033            first_in_memory_block.hash(),
2034            in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
2035        );
2036        // test latest falls back to database state when there's no in-memory block
2037        assert_eq!(
2038            first_db_block.hash(),
2039            only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
2040        );
2041
2042        // test history by block number
2043        assert_eq!(
2044            first_in_memory_block.hash(),
2045            in_memory_provider
2046                .history_by_block_number(first_in_memory_block.number)?
2047                .block_hash(first_in_memory_block.number)?
2048                .unwrap()
2049        );
2050        assert_eq!(
2051            first_db_block.hash(),
2052            only_database_provider
2053                .history_by_block_number(first_db_block.number)?
2054                .block_hash(first_db_block.number)?
2055                .unwrap()
2056        );
2057        assert_eq!(
2058            first_in_memory_block.hash(),
2059            in_memory_provider
2060                .history_by_block_hash(first_in_memory_block.hash())?
2061                .block_hash(first_in_memory_block.number)?
2062                .unwrap()
2063        );
2064        assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
2065
2066        // test state by block hash
2067        assert_eq!(
2068            first_in_memory_block.hash(),
2069            in_memory_provider
2070                .state_by_block_hash(first_in_memory_block.hash())?
2071                .block_hash(first_in_memory_block.number)?
2072                .unwrap()
2073        );
2074        assert_eq!(
2075            first_db_block.hash(),
2076            only_database_provider
2077                .state_by_block_hash(first_db_block.hash())?
2078                .block_hash(first_db_block.number)?
2079                .unwrap()
2080        );
2081        assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
2082
2083        // test pending without pending state- falls back to latest
2084        assert_eq!(
2085            first_in_memory_block.hash(),
2086            in_memory_provider
2087                .pending()
2088                .unwrap()
2089                .block_hash(first_in_memory_block.number)
2090                .unwrap()
2091                .unwrap()
2092        );
2093
2094        // adding a pending block to state can test pending() and  pending_state_by_hash() function
2095        let pending_block = database_blocks[database_blocks.len() - 1].clone();
2096        only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2097            recovered_block: Arc::new(RecoveredBlock::new_sealed(
2098                pending_block.clone(),
2099                Default::default(),
2100            )),
2101            ..Default::default()
2102        });
2103
2104        assert_eq!(
2105            pending_block.hash(),
2106            only_database_provider
2107                .pending()
2108                .unwrap()
2109                .block_hash(pending_block.number)
2110                .unwrap()
2111                .unwrap()
2112        );
2113
2114        assert_eq!(
2115            pending_block.hash(),
2116            only_database_provider
2117                .pending_state_by_hash(pending_block.hash())?
2118                .unwrap()
2119                .block_hash(pending_block.number)?
2120                .unwrap()
2121        );
2122
2123        // test state by block number or tag
2124        assert_eq!(
2125            first_in_memory_block.hash(),
2126            in_memory_provider
2127                .state_by_block_number_or_tag(BlockNumberOrTag::Number(
2128                    first_in_memory_block.number
2129                ))?
2130                .block_hash(first_in_memory_block.number)?
2131                .unwrap()
2132        );
2133        assert_eq!(
2134            first_in_memory_block.hash(),
2135            in_memory_provider
2136                .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
2137                .block_hash(first_in_memory_block.number)?
2138                .unwrap()
2139        );
2140        // test state by block tag for safe block
2141        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2142        in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2143        assert_eq!(
2144            safe_block.hash(),
2145            in_memory_provider
2146                .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
2147                .block_hash(safe_block.number)?
2148                .unwrap()
2149        );
2150        // test state by block tag for finalized block
2151        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2152        in_memory_provider
2153            .canonical_in_memory_state
2154            .set_finalized(finalized_block.clone_sealed_header());
2155        assert_eq!(
2156            finalized_block.hash(),
2157            in_memory_provider
2158                .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
2159                .block_hash(finalized_block.number)?
2160                .unwrap()
2161        );
2162        // test state by block tag for earliest block
2163        let earliest_block = blocks.first().unwrap().clone();
2164        assert_eq!(
2165            earliest_block.hash(),
2166            only_database_provider
2167                .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
2168                .block_hash(earliest_block.number)?
2169                .unwrap()
2170        );
2171
2172        Ok(())
2173    }
2174
2175    #[test]
2176    fn test_block_id_reader() -> eyre::Result<()> {
2177        // Create a new provider
2178        let mut rng = generators::rng();
2179        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2180            &mut rng,
2181            TEST_BLOCKS_COUNT,
2182            TEST_BLOCKS_COUNT,
2183            BlockRangeParams::default(),
2184        )?;
2185
2186        // Set the pending block in memory
2187        let pending_block = in_memory_blocks.last().unwrap();
2188        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2189            recovered_block: Arc::new(RecoveredBlock::new_sealed(
2190                pending_block.clone(),
2191                Default::default(),
2192            )),
2193            ..Default::default()
2194        });
2195
2196        // Set the safe block in memory
2197        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2198        provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2199
2200        // Set the finalized block in memory
2201        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2202        provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
2203
2204        // Verify the pending block number and hash
2205        assert_eq!(
2206            provider.pending_block_num_hash()?,
2207            Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
2208        );
2209
2210        // Verify the safe block number and hash
2211        assert_eq!(
2212            provider.safe_block_num_hash()?,
2213            Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
2214        );
2215
2216        // Verify the finalized block number and hash
2217        assert_eq!(
2218            provider.finalized_block_num_hash()?,
2219            Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
2220        );
2221
2222        Ok(())
2223    }
2224
2225    macro_rules! test_by_tx_range {
2226        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2227
2228            // Get the number methods being tested.
2229            // Since each method tested will move a block from memory to storage, this ensures we have enough.
2230            let extra_blocks = [$(stringify!($method)),*].len();
2231
2232            let mut rng = generators::rng();
2233            let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
2234                &mut rng,
2235                TEST_BLOCKS_COUNT,
2236                TEST_BLOCKS_COUNT + extra_blocks,
2237                BlockRangeParams {
2238                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2239                    ..Default::default()
2240                },
2241            )?;
2242
2243            $(
2244                // Since data moves for each tried method, need to recalculate everything
2245                let db_tx_count =
2246                    database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2247                let in_mem_tx_count =
2248                    in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2249
2250                let db_range = 0..=(db_tx_count - 1);
2251                let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
2252
2253                // Retrieve the expected database data
2254                let database_data =
2255                    database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2256                assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
2257
2258                // Retrieve the expected in-memory data
2259                let in_memory_data =
2260                    in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2261                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
2262
2263                // Test partial in-memory range
2264                assert_eq!(
2265                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2266                    &in_memory_data[1..in_memory_data.len() - 1],
2267                    "partial mem data"
2268                );
2269
2270                // Test range in memory to unbounded end
2271                assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
2272
2273                // Test last element in-memory
2274                assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
2275
2276                // Test range that spans database and in-memory with unbounded end
2277                assert_eq!(
2278                    provider.$method(in_mem_range.start() - 2..)?,
2279                    database_data[database_data.len() - 2..]
2280                        .iter()
2281                        .chain(&in_memory_data[..])
2282                        .cloned()
2283                        .collect::<Vec<_>>(),
2284                    "unbounded span data"
2285                );
2286
2287                // Test range that spans database and in-memory
2288                {
2289                    // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2290                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2291
2292                    assert_eq!(
2293                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2294                        database_data[database_data.len() - 2..]
2295                            .iter()
2296                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2297                            .cloned()
2298                            .collect::<Vec<_>>(),
2299                        "span data"
2300                    );
2301
2302                    // Adjust our blocks accordingly
2303                    database_blocks.push(in_memory_blocks.remove(0));
2304                }
2305
2306                // Test invalid range
2307                let start_tx_num = u64::MAX;
2308                let end_tx_num = u64::MAX;
2309                let result = provider.$method(start_tx_num..end_tx_num)?;
2310                assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2311
2312                // Test empty range
2313                let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2314                assert!(result.is_empty(), "No data should be found for an empty transaction range");
2315            )*
2316        }};
2317    }
2318
2319    #[test]
2320    fn test_methods_by_tx_range() -> eyre::Result<()> {
2321        test_by_tx_range!([
2322            (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2323                .senders()
2324                .unwrap()),
2325            (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2326                .body()
2327                .transactions
2328                .clone()),
2329            (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2330                receipts[block.number as usize].clone()
2331            })
2332        ]);
2333
2334        Ok(())
2335    }
2336
2337    macro_rules! test_by_block_range {
2338        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2339            // Get the number methods being tested.
2340            // Since each method tested will move a block from memory to storage, this ensures we have enough.
2341            let extra_blocks = [$(stringify!($method)),*].len();
2342
2343            let mut rng = generators::rng();
2344            let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2345                &mut rng,
2346                TEST_BLOCKS_COUNT,
2347                TEST_BLOCKS_COUNT + extra_blocks,
2348                BlockRangeParams {
2349                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2350                    ..Default::default()
2351                },
2352            )?;
2353
2354            $(
2355                // Since data moves for each tried method, need to recalculate everything
2356                let db_block_count = database_blocks.len() as u64;
2357                let in_mem_block_count = in_memory_blocks.len() as u64;
2358
2359                let db_range = 0..=db_block_count - 1;
2360                let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2361
2362                // Retrieve the expected database data
2363                let database_data =
2364                    database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2365                assert_eq!(provider.$method(db_range.clone())?, database_data);
2366
2367                // Retrieve the expected in-memory data
2368                let in_memory_data =
2369                    in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2370                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2371
2372                // Test partial in-memory range
2373                assert_eq!(
2374                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2375                    &in_memory_data[1..in_memory_data.len() - 1]
2376                );
2377
2378                // Test range that spans database and in-memory
2379                {
2380
2381                    // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2382                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2383
2384                    assert_eq!(
2385                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2386                        database_data[database_data.len() - 2..]
2387                            .iter()
2388                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2389                            .cloned()
2390                            .collect::<Vec<_>>()
2391                    );
2392
2393                    // Adjust our blocks accordingly
2394                    database_blocks.push(in_memory_blocks.remove(0));
2395                }
2396
2397                // Test invalid range
2398                let start_block_num = u64::MAX;
2399                let end_block_num = u64::MAX;
2400                let result = provider.$method(start_block_num..=end_block_num-1)?;
2401                assert!(result.is_empty(), "No data should be found for an invalid block range");
2402
2403                // Test valid range with empty results
2404                let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2405                assert!(result.is_empty(), "No data should be found for an empty block range");
2406            )*
2407        }};
2408    }
2409
2410    #[test]
2411    fn test_methods_by_block_range() -> eyre::Result<()> {
2412        // todo(joshie) add canonical_hashes_range below after changing its interface into range
2413        // instead start end
2414        test_by_block_range!([
2415            (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2416            (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2417            (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2418            (block_with_senders_range, |block: &SealedBlock<Block>| block
2419                .clone()
2420                .try_recover()
2421                .unwrap()),
2422            (recovered_block_range, |block: &SealedBlock<Block>| block
2423                .clone()
2424                .try_recover()
2425                .unwrap()),
2426            (transactions_by_block_range, |block: &SealedBlock<Block>| block
2427                .body()
2428                .transactions
2429                .clone()),
2430        ]);
2431
2432        Ok(())
2433    }
2434
2435    /// Helper macro to call a provider method based on argument count and check its result
2436    macro_rules! call_method {
2437        ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2438            let result = $provider.$method($($args),*)?;
2439            assert_eq!(
2440                result,
2441                $expected_item,
2442                "{}: item does not match the expected item for arguments {:?}",
2443                stringify!($method),
2444                ($($args),*)
2445            );
2446        }};
2447
2448        // Handle valid or invalid arguments for one argument
2449        (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2450            let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2451            call_method!($provider, $method, (arg), expected_item);
2452        }};
2453
2454        // Handle valid or invalid arguments for two arguments
2455        (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2456            let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2457            call_method!($provider, $method, (arg1, arg2), expected_item);
2458        }};
2459    }
2460
2461    /// Macro to test non-range methods.
2462    ///
2463    /// ( `NUMBER_ARGUMENTS`, METHOD, FN -> ((`METHOD_ARGUMENT(s)`,...), `EXPECTED_RESULT`),
2464    /// `INVALID_ARGUMENTS`)
2465    macro_rules! test_non_range {
2466    ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2467
2468        // Get the number methods being tested.
2469        // Since each method tested will move a block from memory to storage, this ensures we have enough.
2470        let extra_blocks = [$(stringify!($arg_count)),*].len();
2471
2472        let mut rng = generators::rng();
2473        let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2474            &mut rng,
2475            TEST_BLOCKS_COUNT,
2476            TEST_BLOCKS_COUNT + extra_blocks,
2477            BlockRangeParams {
2478                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2479                ..Default::default()
2480            },
2481        )?;
2482
2483        let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2484
2485        $(
2486            let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2487            let tx_num = |block: &SealedBlock<Block>| {
2488                database_blocks
2489                    .iter()
2490                    .chain(in_memory_blocks.iter())
2491                    .take_while(|b| b.number < block.number)
2492                    .map(|b| b.transaction_count())
2493                    .sum::<usize>() as u64
2494            };
2495
2496            // Ensure that the first generated in-memory block exists
2497            {
2498                // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2499                persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2500
2501                call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2502
2503                // Move the block as well in our own structures
2504                database_blocks.push(in_memory_blocks.pop_front().unwrap());
2505            }
2506
2507            // database_blocks is changed above
2508            let tx_num = |block: &SealedBlock<Block>| {
2509                database_blocks
2510                    .iter()
2511                    .chain(in_memory_blocks.iter())
2512                    .take_while(|b| b.number < block.number)
2513                    .map(|b| b.transaction_count())
2514                    .sum::<usize>() as u64
2515            };
2516
2517            // Invalid/Non-existent argument should return `None`
2518            {
2519                call_method!($arg_count, provider, $method, |_,_,_,_|  ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2520            }
2521
2522            // Check that the item is only in memory and not in database
2523            {
2524                let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2525
2526                let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2527                call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2528
2529                // Ensure the item is not in storage
2530                call_method!($arg_count, provider.database, $method, |_,_,_,_|  (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2531            }
2532        )*
2533    }};
2534}
2535
2536    #[test]
2537    fn test_non_range_methods() -> eyre::Result<()> {
2538        let test_tx_index = 0;
2539
2540        test_non_range!([
2541            (
2542                ONE,
2543                header,
2544                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2545                    block.hash(),
2546                    Some(block.header().clone())
2547                ),
2548                B256::random()
2549            ),
2550            (
2551                ONE,
2552                header_by_number,
2553                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2554                    block.number,
2555                    Some(block.header().clone())
2556                ),
2557                u64::MAX
2558            ),
2559            (
2560                ONE,
2561                sealed_header,
2562                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2563                    block.number,
2564                    Some(block.clone_sealed_header())
2565                ),
2566                u64::MAX
2567            ),
2568            (
2569                ONE,
2570                block_hash,
2571                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2572                    block.number,
2573                    Some(block.hash())
2574                ),
2575                u64::MAX
2576            ),
2577            (
2578                ONE,
2579                block_number,
2580                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2581                    block.hash(),
2582                    Some(block.number)
2583                ),
2584                B256::random()
2585            ),
2586            (
2587                ONE,
2588                block,
2589                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2590                    BlockHashOrNumber::Hash(block.hash()),
2591                    Some(block.clone().into_block())
2592                ),
2593                BlockHashOrNumber::Hash(B256::random())
2594            ),
2595            (
2596                ONE,
2597                block,
2598                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2599                    BlockHashOrNumber::Number(block.number),
2600                    Some(block.clone().into_block())
2601                ),
2602                BlockHashOrNumber::Number(u64::MAX)
2603            ),
2604            (
2605                ONE,
2606                block_body_indices,
2607                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2608                    block.number,
2609                    Some(StoredBlockBodyIndices {
2610                        first_tx_num: tx_num,
2611                        tx_count: block.transaction_count() as u64
2612                    })
2613                ),
2614                u64::MAX
2615            ),
2616            (
2617                TWO,
2618                recovered_block,
2619                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2620                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2621                    block.clone().try_recover().ok()
2622                ),
2623                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2624            ),
2625            (
2626                TWO,
2627                recovered_block,
2628                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2629                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2630                    block.clone().try_recover().ok()
2631                ),
2632                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2633            ),
2634            (
2635                TWO,
2636                sealed_block_with_senders,
2637                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2638                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2639                    block.clone().try_recover().ok()
2640                ),
2641                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2642            ),
2643            (
2644                TWO,
2645                sealed_block_with_senders,
2646                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2647                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2648                    block.clone().try_recover().ok()
2649                ),
2650                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2651            ),
2652            (
2653                ONE,
2654                transaction_id,
2655                |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2656                    tx_hash,
2657                    Some(tx_num)
2658                ),
2659                B256::random()
2660            ),
2661            (
2662                ONE,
2663                transaction_by_id,
2664                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2665                    tx_num,
2666                    Some(block.body().transactions[test_tx_index].clone())
2667                ),
2668                u64::MAX
2669            ),
2670            (
2671                ONE,
2672                transaction_by_id_unhashed,
2673                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2674                    tx_num,
2675                    Some(block.body().transactions[test_tx_index].clone())
2676                ),
2677                u64::MAX
2678            ),
2679            (
2680                ONE,
2681                transaction_by_hash,
2682                |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2683                    tx_hash,
2684                    Some(block.body().transactions[test_tx_index].clone())
2685                ),
2686                B256::random()
2687            ),
2688            (
2689                ONE,
2690                block_by_transaction_id,
2691                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2692                    tx_num,
2693                    Some(block.number)
2694                ),
2695                u64::MAX
2696            ),
2697            (
2698                ONE,
2699                transactions_by_block,
2700                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2701                    BlockHashOrNumber::Number(block.number),
2702                    Some(block.body().transactions.clone())
2703                ),
2704                BlockHashOrNumber::Number(u64::MAX)
2705            ),
2706            (
2707                ONE,
2708                transactions_by_block,
2709                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2710                    BlockHashOrNumber::Hash(block.hash()),
2711                    Some(block.body().transactions.clone())
2712                ),
2713                BlockHashOrNumber::Number(u64::MAX)
2714            ),
2715            (
2716                ONE,
2717                transaction_sender,
2718                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2719                    tx_num,
2720                    block.body().transactions[test_tx_index].recover_signer().ok()
2721                ),
2722                u64::MAX
2723            ),
2724            (
2725                ONE,
2726                receipt,
2727                |block: &SealedBlock<Block>,
2728                 tx_num: TxNumber,
2729                 _: B256,
2730                 receipts: &Vec<Vec<Receipt>>| (
2731                    tx_num,
2732                    Some(receipts[block.number as usize][test_tx_index].clone())
2733                ),
2734                u64::MAX
2735            ),
2736            (
2737                ONE,
2738                receipt_by_hash,
2739                |block: &SealedBlock<Block>,
2740                 _: TxNumber,
2741                 tx_hash: B256,
2742                 receipts: &Vec<Vec<Receipt>>| (
2743                    tx_hash,
2744                    Some(receipts[block.number as usize][test_tx_index].clone())
2745                ),
2746                B256::random()
2747            ),
2748            (
2749                ONE,
2750                receipts_by_block,
2751                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2752                    BlockHashOrNumber::Number(block.number),
2753                    Some(receipts[block.number as usize].clone())
2754                ),
2755                BlockHashOrNumber::Number(u64::MAX)
2756            ),
2757            (
2758                ONE,
2759                receipts_by_block,
2760                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2761                    BlockHashOrNumber::Hash(block.hash()),
2762                    Some(receipts[block.number as usize].clone())
2763                ),
2764                BlockHashOrNumber::Hash(B256::random())
2765            ),
2766            // TODO: withdrawals, requests, ommers
2767        ]);
2768
2769        Ok(())
2770    }
2771
2772    #[test]
2773    fn test_race() -> eyre::Result<()> {
2774        let mut rng = generators::rng();
2775        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2776            &mut rng,
2777            TEST_BLOCKS_COUNT - 1,
2778            TEST_BLOCKS_COUNT + 1,
2779            BlockRangeParams {
2780                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2781                ..Default::default()
2782            },
2783        )?;
2784
2785        // Old implementation was querying the database first. This is problematic, if there are
2786        // changes AFTER the database transaction is created.
2787        let old_transaction_hash_fn =
2788            |hash: B256,
2789             canonical_in_memory_state: CanonicalInMemoryState,
2790             factory: ProviderFactory<MockNodeTypesWithDB>| {
2791                assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2792                Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2793            };
2794
2795        // Correct implementation queries in-memory first
2796        let correct_transaction_hash_fn =
2797            |hash: B256,
2798             canonical_in_memory_state: CanonicalInMemoryState,
2799             _factory: ProviderFactory<MockNodeTypesWithDB>| {
2800                if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
2801                    return Ok::<_, ProviderError>(Some(tx));
2802                }
2803                panic!("should not be in database");
2804                // _factory.transaction_by_hash(hash)
2805            };
2806
2807        // OLD BEHAVIOUR
2808        {
2809            // This will persist block 1 AFTER a database is created. Moving it from memory to
2810            // storage.
2811            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2812            let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
2813
2814            // Even though the block exists, given the order of provider queries done in the method
2815            // above, we do not see it.
2816            assert!(matches!(
2817                old_transaction_hash_fn(
2818                    *to_be_persisted_tx.tx_hash(),
2819                    provider.canonical_in_memory_state(),
2820                    provider.database.clone()
2821                ),
2822                Ok(None)
2823            ));
2824        }
2825
2826        // CORRECT BEHAVIOUR
2827        {
2828            // This will persist block 1 AFTER a database is created. Moving it from memory to
2829            // storage.
2830            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
2831            let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
2832
2833            assert_eq!(
2834                correct_transaction_hash_fn(
2835                    *to_be_persisted_tx.tx_hash(),
2836                    provider.canonical_in_memory_state(),
2837                    provider.database
2838                )
2839                .unwrap(),
2840                Some(to_be_persisted_tx)
2841            );
2842        }
2843
2844        Ok(())
2845    }
2846
2847    fn random_account(nonce: u64) -> (Address, Account) {
2848        (Address::random(), Account { nonce, balance: U256::from(nonce), bytecode_hash: None })
2849    }
2850
2851    /// [`BlockchainProvider::new`] needs a genesis header to initialize its chain tracker.
2852    fn test_provider_factory_with_genesis() -> eyre::Result<ProviderFactory<MockNodeTypesWithDB>> {
2853        let factory = create_test_provider_factory();
2854        let provider_rw = factory.provider_rw()?;
2855        let mut rng = generators::rng();
2856        let genesis =
2857            random_block(&mut rng, 0, BlockParams { tx_count: Some(0), ..Default::default() });
2858        provider_rw
2859            .insert_block(&genesis.try_recover().expect("failed to seal block with senders"))?;
2860        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(0))?;
2861        provider_rw.commit()?;
2862        Ok(factory)
2863    }
2864
2865    #[test]
2866    fn state_range_provider_account_range_is_sorted_and_bounded() -> eyre::Result<()> {
2867        let factory = test_provider_factory_with_genesis()?;
2868        let provider_rw = factory.provider_rw()?;
2869
2870        let accounts: Vec<_> = (0..5u64).map(random_account).collect();
2871        provider_rw.insert_account_for_hashing(
2872            accounts.iter().map(|(address, account)| (*address, Some(*account))),
2873        )?;
2874        provider_rw.commit()?;
2875
2876        let provider = BlockchainProvider::new(factory)?;
2877
2878        let mut expected: Vec<_> =
2879            accounts.iter().map(|(address, account)| (keccak256(address), *account)).collect();
2880        expected.sort_by_key(|(hash, _)| *hash);
2881        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2882
2883        let all = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
2884        assert_eq!(all.end, RangeEnd::Exhausted);
2885        assert_eq!(all.items, expected);
2886
2887        // The limit exactly matches the second account's hash, so the range ends there rather
2888        // than by exhausting the trie.
2889        let bounded = state.account_range(B256::ZERO, expected[1].0, 10_000)?;
2890        assert_eq!(bounded.end, RangeEnd::HashLimit);
2891        assert_eq!(bounded.items, expected[..2]);
2892
2893        Ok(())
2894    }
2895
2896    #[test]
2897    fn state_range_provider_account_range_respects_response_bytes() -> eyre::Result<()> {
2898        let factory = test_provider_factory_with_genesis()?;
2899        let provider_rw = factory.provider_rw()?;
2900
2901        let accounts: Vec<_> = (0..5u64).map(random_account).collect();
2902        provider_rw.insert_account_for_hashing(
2903            accounts.iter().map(|(address, account)| (*address, Some(*account))),
2904        )?;
2905        provider_rw.commit()?;
2906
2907        let provider = BlockchainProvider::new(factory)?;
2908        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2909
2910        // Budget only fits a single account.
2911        let partial = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 150)?;
2912        assert_eq!(partial.end, RangeEnd::ByteLimit);
2913        assert_eq!(partial.items.len(), 1);
2914
2915        Ok(())
2916    }
2917
2918    #[test]
2919    fn state_range_provider_storage_range_and_root() -> eyre::Result<()> {
2920        let factory = test_provider_factory_with_genesis()?;
2921        let provider_rw = factory.provider_rw()?;
2922
2923        let (address, account) = random_account(1);
2924        let hashed_address = keccak256(address);
2925        provider_rw.insert_account_for_hashing([(address, Some(account))])?;
2926        let slots = [
2927            StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) },
2928            StorageEntry { key: B256::with_last_byte(2), value: U256::from(20) },
2929        ];
2930        provider_rw.insert_storage_for_hashing([(address, slots)])?;
2931        provider_rw.commit()?;
2932
2933        let provider = BlockchainProvider::new(factory)?;
2934        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2935
2936        let expected_root = provider.latest()?.storage_root(address, HashedStorage::default())?;
2937        assert_eq!(state.storage_root_by_hash(hashed_address)?, expected_root);
2938
2939        let returned = state
2940            .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
2941            .unwrap();
2942        assert_eq!(returned.end, RangeEnd::Exhausted);
2943        let mut expected: Vec<_> =
2944            slots.iter().map(|entry| (keccak256(entry.key), entry.value)).collect();
2945        expected.sort_by_key(|(hash, _)| *hash);
2946        assert_eq!(returned.items, expected);
2947
2948        // `start == limit == ZERO` means the first real slot's hash already reaches the limit.
2949        let empty_window =
2950            state.storage_range(hashed_address, B256::ZERO, B256::ZERO, 10_000)?.unwrap();
2951        assert_eq!(empty_window.end, RangeEnd::HashLimit);
2952        assert_eq!(empty_window.items, expected[..1]);
2953
2954        // An account absent from the trie is distinguished from one with no storage.
2955        assert!(state
2956            .storage_range(B256::repeat_byte(0xee), B256::ZERO, B256::repeat_byte(0xff), 10_000)?
2957            .is_none());
2958
2959        Ok(())
2960    }
2961
2962    #[test]
2963    fn state_range_provider_proofs_start_at_the_real_root() -> eyre::Result<()> {
2964        let factory = test_provider_factory_with_genesis()?;
2965        let provider_rw = factory.provider_rw()?;
2966
2967        let (address, account) = random_account(1);
2968        let hashed_address = keccak256(address);
2969        let hashed_slot = keccak256(B256::with_last_byte(1));
2970        provider_rw.insert_account_for_hashing([(address, Some(account))])?;
2971        provider_rw.insert_storage_for_hashing([(
2972            address,
2973            [StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) }],
2974        )])?;
2975        provider_rw.commit()?;
2976
2977        let provider = BlockchainProvider::new(factory)?;
2978
2979        // The first node of a sorted boundary proof is always the trie root, so this checks the
2980        // proof was generated against the real, current root rather than a stale or empty one.
2981        let state_root = provider.latest()?.state_root(HashedPostState::default())?;
2982        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2983        let account_proof = state.account_range_proof(&[hashed_address])?;
2984        assert!(!account_proof.is_empty());
2985        assert_eq!(keccak256(&account_proof[0]), state_root);
2986
2987        let storage_root = state.storage_root_by_hash(hashed_address)?;
2988        let storage_proof = state.storage_range_proof(hashed_address, &[hashed_slot])?;
2989        assert!(!storage_proof.is_empty());
2990        assert_eq!(keccak256(&storage_proof[0]), storage_root);
2991
2992        Ok(())
2993    }
2994
2995    #[test]
2996    fn state_range_provider_serves_recent_root_and_rejects_expired_root() -> eyre::Result<()> {
2997        let mut rng = generators::rng();
2998        let factory = create_test_provider_factory();
2999        let provider_rw = factory.provider_rw()?;
3000        let expired_root = B256::repeat_byte(0x11);
3001        let recent_root = B256::repeat_byte(0x22);
3002        let mut parent = B256::ZERO;
3003
3004        for number in 0..=SNAPSHOT_STATE_RETENTION {
3005            let mut block = random_block(
3006                &mut rng,
3007                number,
3008                BlockParams { parent: Some(parent), tx_count: Some(0), ..Default::default() },
3009            )
3010            .unseal();
3011            block.header.state_root = match number {
3012                0 => expired_root,
3013                64 => recent_root,
3014                _ => EMPTY_ROOT_HASH,
3015            };
3016            let block = block.seal_slow();
3017            parent = block.hash();
3018            provider_rw
3019                .insert_block(&block.try_recover().expect("failed to seal block with senders"))?;
3020        }
3021        provider_rw.save_stage_checkpoint(
3022            StageId::Finish,
3023            StageCheckpoint::new(SNAPSHOT_STATE_RETENTION),
3024        )?;
3025        provider_rw.commit()?;
3026
3027        let provider = BlockchainProvider::new(factory)?;
3028        assert!(provider.state_range_provider(recent_root)?.is_some());
3029        assert!(provider.state_range_provider(expired_root)?.is_none());
3030
3031        Ok(())
3032    }
3033
3034    #[test]
3035    fn state_range_provider_serves_persisted_root_with_in_memory_overlay() -> eyre::Result<()> {
3036        let mut rng = generators::rng();
3037        let (provider, _, _, _) = provider_with_random_blocks(
3038            &mut rng,
3039            TEST_BLOCKS_COUNT - 1,
3040            1,
3041            BlockRangeParams::default(),
3042        )?;
3043        assert!(provider.canonical_in_memory_state.head_state().is_some());
3044        let provider_rw = provider.database.provider_rw()?;
3045        provider_rw.save_stage_checkpoint(
3046            StageId::Finish,
3047            StageCheckpoint::new((TEST_BLOCKS_COUNT - 2) as u64),
3048        )?;
3049        provider_rw.commit()?;
3050
3051        assert!(provider.state_range_provider(EMPTY_ROOT_HASH)?.is_some());
3052
3053        Ok(())
3054    }
3055
3056    #[test]
3057    fn state_range_provider_resolves_root_from_in_memory_block() -> eyre::Result<()> {
3058        let mut rng = generators::rng();
3059        let factory = test_provider_factory_with_genesis()?;
3060        let provider = BlockchainProvider::new(factory)?;
3061
3062        let (address, account) = random_account(1);
3063        let hashed_address = keccak256(address);
3064        let mut hashed_state = HashedPostState::default();
3065        hashed_state.accounts.insert(hashed_address, Some(account));
3066
3067        // A root only the in-memory block carries, so a match proves the in-memory path (not
3068        // persisted history, which has no block with this root) resolved it.
3069        let unique_root = B256::repeat_byte(0x77);
3070        let parent = provider.canonical_in_memory_state.get_canonical_head();
3071        let mut block = random_block(
3072            &mut rng,
3073            parent.number + 1,
3074            BlockParams { parent: Some(parent.hash()), tx_count: Some(0), ..Default::default() },
3075        )
3076        .unseal();
3077        block.header.state_root = unique_root;
3078        let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3079
3080        let trie_data = ComputedTrieData::new(
3081            Arc::new(hashed_state.into_sorted()),
3082            Arc::new(TrieUpdates::default().into_sorted()),
3083        );
3084        let execution_output = BlockExecutionOutput {
3085            result: BlockExecutionResult {
3086                receipts: Default::default(),
3087                requests: Default::default(),
3088                gas_used: 0,
3089                blob_gas_used: 0,
3090            },
3091            state: Default::default(),
3092        };
3093        let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3094        provider
3095            .canonical_in_memory_state
3096            .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3097
3098        let state =
3099            provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3100        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3101        assert_eq!(range.items, vec![(hashed_address, account)]);
3102
3103        Ok(())
3104    }
3105
3106    #[test]
3107    fn state_range_provider_reverts_database_advancement_past_anchor() -> eyre::Result<()> {
3108        let mut rng = generators::rng();
3109        let factory = test_provider_factory_with_genesis()?;
3110        let provider = BlockchainProvider::new(factory)?;
3111        let genesis = provider.canonical_in_memory_state.get_canonical_head();
3112
3113        // In-memory target block anchored on genesis, with a known account.
3114        let (target_address, target_account) = random_account(1);
3115        let target_hashed = keccak256(target_address);
3116        let mut target_state = HashedPostState::default();
3117        target_state.accounts.insert(target_hashed, Some(target_account));
3118
3119        let unique_root = B256::repeat_byte(0x77);
3120        let mut block = random_block(
3121            &mut rng,
3122            genesis.number + 1,
3123            BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3124        )
3125        .unseal();
3126        block.header.state_root = unique_root;
3127        let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3128        let trie_data = ComputedTrieData::new(
3129            Arc::new(target_state.into_sorted()),
3130            Arc::new(TrieUpdates::default().into_sorted()),
3131        );
3132        let execution_output = BlockExecutionOutput {
3133            result: BlockExecutionResult {
3134                receipts: Default::default(),
3135                requests: Default::default(),
3136                gas_used: 0,
3137                blob_gas_used: 0,
3138            },
3139            state: Default::default(),
3140        };
3141        let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3142        provider
3143            .canonical_in_memory_state
3144            .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3145
3146        // Persistence races ahead: a *different* block, with a *different* account, lands in
3147        // the database on top of the same genesis anchor while the in-memory chain above still
3148        // references genesis as its anchor.
3149        let (noise_address, noise_account) = random_account(2);
3150        let noise_block = random_block(
3151            &mut rng,
3152            genesis.number + 1,
3153            BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3154        )
3155        .try_recover()
3156        .expect("failed to seal block with senders");
3157        let mut noise_state = HashedPostState::default();
3158        noise_state.accounts.insert(keccak256(noise_address), Some(noise_account));
3159        let provider_rw = provider.database.provider_rw()?;
3160        provider_rw.append_blocks_with_state(
3161            vec![noise_block],
3162            &ExecutionOutcome {
3163                bundle: BundleState::new(
3164                    [(noise_address, None, Some(noise_account.into()), Default::default())],
3165                    [[(noise_address, Some(None), [])]],
3166                    [],
3167                ),
3168                first_block: genesis.number + 1,
3169                ..Default::default()
3170            },
3171            noise_state.into_sorted(),
3172        )?;
3173        provider_rw
3174            .save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(genesis.number + 1))?;
3175        provider_rw.commit()?;
3176
3177        // Resolving the in-memory root must revert the database's advancement back to genesis,
3178        // so the noise account must not leak into the result.
3179        let state =
3180            provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3181        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3182        assert_eq!(range.items, vec![(target_hashed, target_account)]);
3183
3184        Ok(())
3185    }
3186
3187    #[test]
3188    fn historical_state_range_provider_reverts_state_change_past_retained_anchor(
3189    ) -> eyre::Result<()> {
3190        let mut rng = generators::rng();
3191
3192        // State A: the account and its one storage slot as of the retained anchor.
3193        let (address, account_a) = random_account(1);
3194        let hashed_address = keccak256(address);
3195        let slot_key = B256::with_last_byte(1);
3196        let slot = U256::from_be_bytes(slot_key.0);
3197        let hashed_slot = keccak256(slot_key);
3198        let value_a = U256::from(1);
3199
3200        let factory = test_provider_factory_with_genesis()?;
3201        let provider_rw = factory.provider_rw()?;
3202        provider_rw.insert_account_for_hashing([(address, Some(account_a))])?;
3203        provider_rw.insert_storage_for_hashing([(
3204            address,
3205            [StorageEntry { key: slot_key, value: value_a }],
3206        )])?;
3207        provider_rw.commit()?;
3208        let anchor_root = factory.latest()?.state_root(HashedPostState::default())?;
3209
3210        let genesis_hash = factory.sealed_header(0)?.unwrap().hash();
3211        let mut anchor_block = random_block(
3212            &mut rng,
3213            1,
3214            BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
3215        )
3216        .unseal();
3217        anchor_block.header.state_root = anchor_root;
3218        let anchor_block =
3219            anchor_block.seal_slow().try_recover().expect("failed to seal block with senders");
3220        let anchor_hash = anchor_block.hash();
3221
3222        let provider_rw = factory.provider_rw()?;
3223        provider_rw.insert_block(&anchor_block)?;
3224        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1))?;
3225        provider_rw.commit()?;
3226
3227        // State B: a later block changes both the account and its storage slot.
3228        let account_b = Account { nonce: 2, balance: U256::from(2), ..account_a };
3229        let value_b = U256::from(2);
3230
3231        let mut storage = HashMap::default();
3232        storage.insert(slot, (value_a, value_b));
3233
3234        let mut state_b = HashedPostState::default();
3235        state_b.accounts.insert(hashed_address, Some(account_b));
3236        state_b
3237            .storages
3238            .insert(hashed_address, HashedStorage::from_iter(false, [(hashed_slot, value_b)]));
3239
3240        let state_b_root = factory.latest()?.state_root(state_b.clone())?;
3241        let mut later_block = random_block(
3242            &mut rng,
3243            2,
3244            BlockParams { parent: Some(anchor_hash), tx_count: Some(0), ..Default::default() },
3245        )
3246        .unseal();
3247        later_block.header.state_root = state_b_root;
3248        let later_block =
3249            later_block.seal_slow().try_recover().expect("failed to seal block with senders");
3250
3251        let provider_rw = factory.provider_rw()?;
3252        provider_rw.append_blocks_with_state(
3253            vec![later_block],
3254            &ExecutionOutcome {
3255                bundle: BundleState::new(
3256                    [(address, Some(account_a.into()), Some(account_b.into()), storage)],
3257                    [[(address, Some(Some(account_a.into())), [(slot, value_a)])]],
3258                    [],
3259                ),
3260                first_block: 2,
3261                ..Default::default()
3262            },
3263            state_b.into_sorted(),
3264        )?;
3265        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(2))?;
3266        provider_rw.commit()?;
3267
3268        // Resolving the anchor root must revert the later account and storage changes; state B
3269        // must not leak into the response.
3270        let provider = BlockchainProvider::new(factory)?;
3271        let state =
3272            provider.state_range_provider(anchor_root)?.expect("retained root must resolve");
3273        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3274        assert_eq!(range.items, vec![(hashed_address, account_a)]);
3275
3276        let storage_range = state
3277            .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3278            .expect("account must have storage");
3279        assert_eq!(storage_range.items, vec![(hashed_slot, value_a)]);
3280
3281        Ok(())
3282    }
3283}