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