reth_storage_api/
noop.rs

1//! Various noop implementations for traits.
2
3use crate::{
4    AccountReader, BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader,
5    BlockReader, BlockReaderIdExt, BlockSource, BytecodeReader, ChangeSetReader,
6    HashedPostStateProvider, HeaderProvider, NodePrimitivesProvider, PruneCheckpointReader,
7    ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProofProvider,
8    StateProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider,
9    StorageRootProvider, TransactionVariant, TransactionsProvider,
10};
11
12#[cfg(feature = "db-api")]
13use crate::{DBProvider, DatabaseProviderFactory};
14use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
15use alloy_consensus::transaction::TransactionMeta;
16use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag};
17use alloy_primitives::{
18    Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, TxNumber, B256, U256,
19};
20use core::{
21    fmt::Debug,
22    marker::PhantomData,
23    ops::{RangeBounds, RangeInclusive},
24};
25use reth_chainspec::{ChainInfo, ChainSpecProvider, EthChainSpec, MAINNET};
26#[cfg(feature = "db-api")]
27use reth_db_api::mock::{DatabaseMock, TxMock};
28use reth_db_models::{AccountBeforeTx, StoredBlockBodyIndices};
29use reth_ethereum_primitives::EthPrimitives;
30use reth_execution_types::ExecutionOutcome;
31use reth_primitives_traits::{Account, Bytecode, NodePrimitives, RecoveredBlock, SealedHeader};
32#[cfg(feature = "db-api")]
33use reth_prune_types::PruneModes;
34use reth_prune_types::{PruneCheckpoint, PruneSegment};
35use reth_stages_types::{StageCheckpoint, StageId};
36use reth_storage_errors::provider::{ProviderError, ProviderResult};
37use reth_trie_common::{
38    updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
39    MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
40};
41
42/// Supports various api interfaces for testing purposes.
43#[derive(Debug)]
44#[non_exhaustive]
45pub struct NoopProvider<ChainSpec = reth_chainspec::ChainSpec, N = EthPrimitives> {
46    chain_spec: Arc<ChainSpec>,
47    #[cfg(feature = "db-api")]
48    tx: TxMock,
49    #[cfg(feature = "db-api")]
50    prune_modes: PruneModes,
51    _phantom: PhantomData<N>,
52}
53
54impl<ChainSpec, N> NoopProvider<ChainSpec, N> {
55    /// Create a new instance for specific primitive types.
56    pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
57        Self {
58            chain_spec,
59            #[cfg(feature = "db-api")]
60            tx: TxMock::default(),
61            #[cfg(feature = "db-api")]
62            prune_modes: PruneModes::none(),
63            _phantom: Default::default(),
64        }
65    }
66}
67
68impl<ChainSpec> NoopProvider<ChainSpec> {
69    /// Create a new instance of the `NoopBlockReader`.
70    pub fn eth(chain_spec: Arc<ChainSpec>) -> Self {
71        Self {
72            chain_spec,
73            #[cfg(feature = "db-api")]
74            tx: TxMock::default(),
75            #[cfg(feature = "db-api")]
76            prune_modes: PruneModes::none(),
77            _phantom: Default::default(),
78        }
79    }
80}
81
82impl NoopProvider {
83    /// Create a new instance of the [`NoopProvider`] with the mainnet chain spec.
84    pub fn mainnet() -> Self {
85        Self::eth(MAINNET.clone())
86    }
87}
88
89impl Default for NoopProvider {
90    fn default() -> Self {
91        Self::mainnet()
92    }
93}
94
95impl<ChainSpec, N> Clone for NoopProvider<ChainSpec, N> {
96    fn clone(&self) -> Self {
97        Self {
98            chain_spec: Arc::clone(&self.chain_spec),
99            #[cfg(feature = "db-api")]
100            tx: self.tx.clone(),
101            #[cfg(feature = "db-api")]
102            prune_modes: self.prune_modes.clone(),
103            _phantom: Default::default(),
104        }
105    }
106}
107
108/// Noop implementation for testing purposes
109impl<ChainSpec: Send + Sync, N: Send + Sync> BlockHashReader for NoopProvider<ChainSpec, N> {
110    fn block_hash(&self, _number: u64) -> ProviderResult<Option<B256>> {
111        Ok(None)
112    }
113
114    fn canonical_hashes_range(
115        &self,
116        _start: BlockNumber,
117        _end: BlockNumber,
118    ) -> ProviderResult<Vec<B256>> {
119        Ok(Vec::new())
120    }
121}
122
123impl<ChainSpec: Send + Sync, N: Send + Sync> BlockNumReader for NoopProvider<ChainSpec, N> {
124    fn chain_info(&self) -> ProviderResult<ChainInfo> {
125        Ok(ChainInfo::default())
126    }
127
128    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
129        Ok(0)
130    }
131
132    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
133        Ok(0)
134    }
135
136    fn block_number(&self, _hash: B256) -> ProviderResult<Option<BlockNumber>> {
137        Ok(None)
138    }
139}
140
141impl<ChainSpec: EthChainSpec + 'static, N: Debug + Send + Sync + 'static> ChainSpecProvider
142    for NoopProvider<ChainSpec, N>
143{
144    type ChainSpec = ChainSpec;
145
146    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
147        self.chain_spec.clone()
148    }
149}
150
151impl<C: Send + Sync, N: NodePrimitives> BlockIdReader for NoopProvider<C, N> {
152    fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
153        Ok(None)
154    }
155
156    fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
157        Ok(None)
158    }
159
160    fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
161        Ok(None)
162    }
163}
164
165impl<C: Send + Sync, N: NodePrimitives> BlockReaderIdExt for NoopProvider<C, N> {
166    fn block_by_id(&self, _id: BlockId) -> ProviderResult<Option<N::Block>> {
167        Ok(None)
168    }
169
170    fn sealed_header_by_id(
171        &self,
172        _id: BlockId,
173    ) -> ProviderResult<Option<SealedHeader<N::BlockHeader>>> {
174        Ok(None)
175    }
176
177    fn header_by_id(&self, _id: BlockId) -> ProviderResult<Option<N::BlockHeader>> {
178        Ok(None)
179    }
180}
181
182impl<C: Send + Sync, N: NodePrimitives> BlockReader for NoopProvider<C, N> {
183    type Block = N::Block;
184
185    fn find_block_by_hash(
186        &self,
187        _hash: B256,
188        _source: BlockSource,
189    ) -> ProviderResult<Option<Self::Block>> {
190        Ok(None)
191    }
192
193    fn block(&self, _id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
194        Ok(None)
195    }
196
197    fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
198        Ok(None)
199    }
200
201    fn pending_block_and_receipts(
202        &self,
203    ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
204        Ok(None)
205    }
206
207    fn recovered_block(
208        &self,
209        _id: BlockHashOrNumber,
210        _transaction_kind: TransactionVariant,
211    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
212        Ok(None)
213    }
214
215    fn sealed_block_with_senders(
216        &self,
217        _id: BlockHashOrNumber,
218        _transaction_kind: TransactionVariant,
219    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
220        Ok(None)
221    }
222
223    fn block_range(&self, _range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
224        Ok(Vec::new())
225    }
226
227    fn block_with_senders_range(
228        &self,
229        _range: RangeInclusive<BlockNumber>,
230    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
231        Ok(Vec::new())
232    }
233
234    fn recovered_block_range(
235        &self,
236        _range: RangeInclusive<BlockNumber>,
237    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
238        Ok(Vec::new())
239    }
240
241    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
242        Ok(None)
243    }
244}
245
246impl<C: Send + Sync, N: NodePrimitives> TransactionsProvider for NoopProvider<C, N> {
247    type Transaction = N::SignedTx;
248
249    fn transaction_id(&self, _tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
250        Ok(None)
251    }
252
253    fn transaction_by_id(&self, _id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
254        Ok(None)
255    }
256
257    fn transaction_by_id_unhashed(
258        &self,
259        _id: TxNumber,
260    ) -> ProviderResult<Option<Self::Transaction>> {
261        Ok(None)
262    }
263
264    fn transaction_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
265        Ok(None)
266    }
267
268    fn transaction_by_hash_with_meta(
269        &self,
270        _hash: TxHash,
271    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
272        Ok(None)
273    }
274
275    fn transaction_block(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
276        Ok(None)
277    }
278
279    fn transactions_by_block(
280        &self,
281        _block_id: BlockHashOrNumber,
282    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
283        Ok(None)
284    }
285
286    fn transactions_by_block_range(
287        &self,
288        _range: impl RangeBounds<BlockNumber>,
289    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
290        Ok(Vec::default())
291    }
292
293    fn transactions_by_tx_range(
294        &self,
295        _range: impl RangeBounds<TxNumber>,
296    ) -> ProviderResult<Vec<Self::Transaction>> {
297        Ok(Vec::default())
298    }
299
300    fn senders_by_tx_range(
301        &self,
302        _range: impl RangeBounds<TxNumber>,
303    ) -> ProviderResult<Vec<Address>> {
304        Ok(Vec::default())
305    }
306
307    fn transaction_sender(&self, _id: TxNumber) -> ProviderResult<Option<Address>> {
308        Ok(None)
309    }
310}
311
312impl<C: Send + Sync, N: NodePrimitives> ReceiptProvider for NoopProvider<C, N> {
313    type Receipt = N::Receipt;
314
315    fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
316        Ok(None)
317    }
318
319    fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
320        Ok(None)
321    }
322
323    fn receipts_by_block(
324        &self,
325        _block: BlockHashOrNumber,
326    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
327        Ok(None)
328    }
329
330    fn receipts_by_tx_range(
331        &self,
332        _range: impl RangeBounds<TxNumber>,
333    ) -> ProviderResult<Vec<Self::Receipt>> {
334        Ok(Vec::new())
335    }
336
337    fn receipts_by_block_range(
338        &self,
339        _block_range: RangeInclusive<BlockNumber>,
340    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
341        Ok(Vec::new())
342    }
343}
344
345impl<C: Send + Sync, N: NodePrimitives> ReceiptProviderIdExt for NoopProvider<C, N> {}
346
347impl<C: Send + Sync, N: NodePrimitives> HeaderProvider for NoopProvider<C, N> {
348    type Header = N::BlockHeader;
349
350    fn header(&self, _block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
351        Ok(None)
352    }
353
354    fn header_by_number(&self, _num: u64) -> ProviderResult<Option<Self::Header>> {
355        Ok(None)
356    }
357
358    fn header_td(&self, _hash: BlockHash) -> ProviderResult<Option<U256>> {
359        Ok(None)
360    }
361
362    fn header_td_by_number(&self, _number: BlockNumber) -> ProviderResult<Option<U256>> {
363        Ok(None)
364    }
365
366    fn headers_range(
367        &self,
368        _range: impl RangeBounds<BlockNumber>,
369    ) -> ProviderResult<Vec<Self::Header>> {
370        Ok(Vec::new())
371    }
372
373    fn sealed_header(
374        &self,
375        _number: BlockNumber,
376    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
377        Ok(None)
378    }
379
380    fn sealed_headers_while(
381        &self,
382        _range: impl RangeBounds<BlockNumber>,
383        _predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
384    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
385        Ok(Vec::new())
386    }
387}
388
389impl<C: Send + Sync, N: NodePrimitives> AccountReader for NoopProvider<C, N> {
390    fn basic_account(&self, _address: &Address) -> ProviderResult<Option<Account>> {
391        Ok(None)
392    }
393}
394
395impl<C: Send + Sync, N: NodePrimitives> ChangeSetReader for NoopProvider<C, N> {
396    fn account_block_changeset(
397        &self,
398        _block_number: BlockNumber,
399    ) -> ProviderResult<Vec<AccountBeforeTx>> {
400        Ok(Vec::default())
401    }
402
403    fn get_account_before_block(
404        &self,
405        _block_number: BlockNumber,
406        _address: Address,
407    ) -> ProviderResult<Option<AccountBeforeTx>> {
408        Ok(None)
409    }
410}
411
412impl<C: Send + Sync, N: NodePrimitives> StateRootProvider for NoopProvider<C, N> {
413    fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
414        Ok(B256::default())
415    }
416
417    fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
418        Ok(B256::default())
419    }
420
421    fn state_root_with_updates(
422        &self,
423        _state: HashedPostState,
424    ) -> ProviderResult<(B256, TrieUpdates)> {
425        Ok((B256::default(), TrieUpdates::default()))
426    }
427
428    fn state_root_from_nodes_with_updates(
429        &self,
430        _input: TrieInput,
431    ) -> ProviderResult<(B256, TrieUpdates)> {
432        Ok((B256::default(), TrieUpdates::default()))
433    }
434}
435
436impl<C: Send + Sync, N: NodePrimitives> StorageRootProvider for NoopProvider<C, N> {
437    fn storage_root(
438        &self,
439        _address: Address,
440        _hashed_storage: HashedStorage,
441    ) -> ProviderResult<B256> {
442        Ok(B256::default())
443    }
444
445    fn storage_proof(
446        &self,
447        _address: Address,
448        slot: B256,
449        _hashed_storage: HashedStorage,
450    ) -> ProviderResult<StorageProof> {
451        Ok(StorageProof::new(slot))
452    }
453
454    fn storage_multiproof(
455        &self,
456        _address: Address,
457        _slots: &[B256],
458        _hashed_storage: HashedStorage,
459    ) -> ProviderResult<StorageMultiProof> {
460        Ok(StorageMultiProof::empty())
461    }
462}
463
464impl<C: Send + Sync, N: NodePrimitives> StateProofProvider for NoopProvider<C, N> {
465    fn proof(
466        &self,
467        _input: TrieInput,
468        address: Address,
469        _slots: &[B256],
470    ) -> ProviderResult<AccountProof> {
471        Ok(AccountProof::new(address))
472    }
473
474    fn multiproof(
475        &self,
476        _input: TrieInput,
477        _targets: MultiProofTargets,
478    ) -> ProviderResult<MultiProof> {
479        Ok(MultiProof::default())
480    }
481
482    fn witness(&self, _input: TrieInput, _target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
483        Ok(Vec::default())
484    }
485}
486
487impl<C: Send + Sync, N: NodePrimitives> HashedPostStateProvider for NoopProvider<C, N> {
488    fn hashed_post_state(&self, _bundle_state: &revm_database::BundleState) -> HashedPostState {
489        HashedPostState::default()
490    }
491}
492
493impl<C: Send + Sync, N: NodePrimitives> StateReader for NoopProvider<C, N> {
494    type Receipt = N::Receipt;
495
496    fn get_state(
497        &self,
498        _block: BlockNumber,
499    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
500        Ok(None)
501    }
502}
503
504impl<C: Send + Sync, N: NodePrimitives> StateProvider for NoopProvider<C, N> {
505    fn storage(
506        &self,
507        _account: Address,
508        _storage_key: StorageKey,
509    ) -> ProviderResult<Option<StorageValue>> {
510        Ok(None)
511    }
512}
513
514impl<C: Send + Sync, N: NodePrimitives> BytecodeReader for NoopProvider<C, N> {
515    fn bytecode_by_hash(&self, _code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
516        Ok(None)
517    }
518}
519
520impl<C: Send + Sync + 'static, N: NodePrimitives> StateProviderFactory for NoopProvider<C, N> {
521    fn latest(&self) -> ProviderResult<StateProviderBox> {
522        Ok(Box::new(self.clone()))
523    }
524
525    fn state_by_block_number_or_tag(
526        &self,
527        number_or_tag: BlockNumberOrTag,
528    ) -> ProviderResult<StateProviderBox> {
529        match number_or_tag {
530            BlockNumberOrTag::Latest => self.latest(),
531            BlockNumberOrTag::Finalized => {
532                // we can only get the finalized state by hash, not by num
533                let hash =
534                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
535
536                // only look at historical state
537                self.history_by_block_hash(hash)
538            }
539            BlockNumberOrTag::Safe => {
540                // we can only get the safe state by hash, not by num
541                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
542
543                self.history_by_block_hash(hash)
544            }
545            BlockNumberOrTag::Earliest => {
546                self.history_by_block_number(self.earliest_block_number()?)
547            }
548            BlockNumberOrTag::Pending => self.pending(),
549            BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
550        }
551    }
552
553    fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
554        Ok(Box::new(self.clone()))
555    }
556
557    fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
558        Ok(Box::new(self.clone()))
559    }
560
561    fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
562        Ok(Box::new(self.clone()))
563    }
564
565    fn pending(&self) -> ProviderResult<StateProviderBox> {
566        Ok(Box::new(self.clone()))
567    }
568
569    fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
570        Ok(Some(Box::new(self.clone())))
571    }
572
573    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
574        Ok(Some(Box::new(self.clone())))
575    }
576}
577
578impl<C: Send + Sync, N: NodePrimitives> StageCheckpointReader for NoopProvider<C, N> {
579    fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
580        Ok(None)
581    }
582
583    fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
584        Ok(None)
585    }
586
587    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
588        Ok(Vec::new())
589    }
590}
591
592impl<C: Send + Sync, N: NodePrimitives> PruneCheckpointReader for NoopProvider<C, N> {
593    fn get_prune_checkpoint(
594        &self,
595        _segment: PruneSegment,
596    ) -> ProviderResult<Option<PruneCheckpoint>> {
597        Ok(None)
598    }
599
600    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
601        Ok(Vec::new())
602    }
603}
604
605impl<C: Send + Sync, N: NodePrimitives> NodePrimitivesProvider for NoopProvider<C, N> {
606    type Primitives = N;
607}
608
609impl<C: Send + Sync, N: Send + Sync> BlockBodyIndicesProvider for NoopProvider<C, N> {
610    fn block_body_indices(&self, _num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
611        Ok(None)
612    }
613
614    fn block_body_indices_range(
615        &self,
616        _range: RangeInclusive<BlockNumber>,
617    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
618        Ok(Vec::new())
619    }
620}
621
622#[cfg(feature = "db-api")]
623impl<ChainSpec: Send + Sync, N: NodePrimitives> DBProvider for NoopProvider<ChainSpec, N> {
624    type Tx = TxMock;
625
626    fn tx_ref(&self) -> &Self::Tx {
627        &self.tx
628    }
629
630    fn tx_mut(&mut self) -> &mut Self::Tx {
631        &mut self.tx
632    }
633
634    fn into_tx(self) -> Self::Tx {
635        self.tx
636    }
637
638    fn prune_modes_ref(&self) -> &PruneModes {
639        &self.prune_modes
640    }
641
642    fn commit(self) -> ProviderResult<bool> {
643        use reth_db_api::transaction::DbTx;
644
645        Ok(self.tx.commit()?)
646    }
647}
648
649#[cfg(feature = "db-api")]
650impl<ChainSpec: Send + Sync, N: NodePrimitives> DatabaseProviderFactory
651    for NoopProvider<ChainSpec, N>
652{
653    type DB = DatabaseMock;
654    type Provider = Self;
655    type ProviderRW = Self;
656
657    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
658        Ok(self.clone())
659    }
660
661    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
662        Ok(self.clone())
663    }
664}