Skip to main content

reth_provider/providers/
blockchain_provider.rs

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