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