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