1use crate::{
2 traits::{BlockSource, ReceiptProvider},
3 AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
4 ChainSpecProvider, ChangeSetReader, HeaderProvider, PruneCheckpointReader,
5 ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory, StateReader,
6 StateRootProvider, TransactionVariant, TransactionsProvider,
7};
8use alloy_consensus::{
9 constants::EMPTY_ROOT_HASH,
10 transaction::{TransactionMeta, TxHashRef},
11 BlockHeader,
12};
13use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag};
14use alloy_primitives::{
15 keccak256, map::HashMap, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue,
16 TxHash, TxNumber, B256, U256,
17};
18use parking_lot::Mutex;
19use reth_chain_state::{CanonStateNotifications, CanonStateSubscriptions};
20use reth_chainspec::{ChainInfo, EthChainSpec};
21use reth_db::transaction::DbTx;
22use reth_db_api::{
23 mock::{DatabaseMock, TxMock},
24 models::{AccountBeforeTx, StoredBlockBodyIndices},
25};
26use reth_ethereum_primitives::EthPrimitives;
27use reth_execution_types::ExecutionOutcome;
28use reth_primitives_traits::{
29 Account, Block, BlockBody, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedHeader,
30 SignerRecoverable, StorageEntry,
31};
32use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
33use reth_stages_types::{StageCheckpoint, StageId};
34use reth_storage_api::{
35 BlockBodyIndicesProvider, BytecodeReader, DBProvider, DatabaseProviderFactory,
36 HashedPostStateProvider, NodePrimitivesProvider, StageCheckpointReader, StateProofProvider,
37 StorageChangeSetReader, StorageRootProvider,
38};
39use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
40use reth_trie::{
41 updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
42 MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
43};
44use std::{
45 collections::BTreeMap,
46 fmt::Debug,
47 ops::{RangeBounds, RangeInclusive},
48 sync::Arc,
49};
50use tokio::sync::broadcast;
51
52#[derive(Debug)]
54pub struct MockEthProvider<T: NodePrimitives = EthPrimitives, ChainSpec = reth_chainspec::ChainSpec>
55{
56 pub blocks: Arc<Mutex<HashMap<B256, T::Block>>>,
58 pub headers: Arc<Mutex<HashMap<B256, <T::Block as Block>::Header>>>,
60 pub receipts: Arc<Mutex<HashMap<BlockNumber, Vec<T::Receipt>>>>,
62 pub accounts: Arc<Mutex<HashMap<Address, ExtendedAccount>>>,
64 pub chain_spec: Arc<ChainSpec>,
66 pub state_roots: Arc<Mutex<Vec<B256>>>,
68 pub block_body_indices: Arc<Mutex<HashMap<BlockNumber, StoredBlockBodyIndices>>>,
70 tx: TxMock,
71 prune_modes: Arc<PruneModes>,
72}
73
74impl<T: NodePrimitives, ChainSpec> Clone for MockEthProvider<T, ChainSpec>
75where
76 T::Block: Clone,
77{
78 fn clone(&self) -> Self {
79 Self {
80 blocks: self.blocks.clone(),
81 headers: self.headers.clone(),
82 receipts: self.receipts.clone(),
83 accounts: self.accounts.clone(),
84 chain_spec: self.chain_spec.clone(),
85 state_roots: self.state_roots.clone(),
86 block_body_indices: self.block_body_indices.clone(),
87 tx: self.tx.clone(),
88 prune_modes: self.prune_modes.clone(),
89 }
90 }
91}
92
93impl<T: NodePrimitives> MockEthProvider<T, reth_chainspec::ChainSpec> {
94 pub fn new() -> Self {
96 Self {
97 blocks: Default::default(),
98 headers: Default::default(),
99 receipts: Default::default(),
100 accounts: Default::default(),
101 chain_spec: Arc::new(reth_chainspec::ChainSpecBuilder::mainnet().build()),
102 state_roots: Default::default(),
103 block_body_indices: Default::default(),
104 tx: Default::default(),
105 prune_modes: Default::default(),
106 }
107 }
108}
109
110impl<T: NodePrimitives, ChainSpec> MockEthProvider<T, ChainSpec> {
111 pub fn add_block(&self, hash: B256, block: T::Block) {
113 self.add_header(hash, block.header().clone());
114 self.blocks.lock().insert(hash, block);
115 }
116
117 pub fn extend_blocks(&self, iter: impl IntoIterator<Item = (B256, T::Block)>) {
119 for (hash, block) in iter {
120 self.add_block(hash, block)
121 }
122 }
123
124 pub fn add_header(&self, hash: B256, header: <T::Block as Block>::Header) {
126 self.headers.lock().insert(hash, header);
127 }
128
129 pub fn extend_headers(
131 &self,
132 iter: impl IntoIterator<Item = (B256, <T::Block as Block>::Header)>,
133 ) {
134 for (hash, header) in iter {
135 self.add_header(hash, header)
136 }
137 }
138
139 pub fn add_account(&self, address: Address, account: ExtendedAccount) {
141 self.accounts.lock().insert(address, account);
142 }
143
144 pub fn extend_accounts(&self, iter: impl IntoIterator<Item = (Address, ExtendedAccount)>) {
146 for (address, account) in iter {
147 self.add_account(address, account)
148 }
149 }
150
151 pub fn add_receipts(&self, block_number: BlockNumber, receipts: Vec<T::Receipt>) {
153 self.receipts.lock().insert(block_number, receipts);
154 }
155
156 pub fn extend_receipts(&self, iter: impl IntoIterator<Item = (BlockNumber, Vec<T::Receipt>)>) {
158 for (block_number, receipts) in iter {
159 self.add_receipts(block_number, receipts);
160 }
161 }
162
163 pub fn add_block_body_indices(
165 &self,
166 block_number: BlockNumber,
167 indices: StoredBlockBodyIndices,
168 ) {
169 self.block_body_indices.lock().insert(block_number, indices);
170 }
171
172 pub fn add_state_root(&self, state_root: B256) {
174 self.state_roots.lock().push(state_root);
175 }
176
177 pub fn with_chain_spec<C>(self, chain_spec: C) -> MockEthProvider<T, C> {
179 MockEthProvider {
180 blocks: self.blocks,
181 headers: self.headers,
182 receipts: self.receipts,
183 accounts: self.accounts,
184 chain_spec: Arc::new(chain_spec),
185 state_roots: self.state_roots,
186 block_body_indices: self.block_body_indices,
187 tx: self.tx,
188 prune_modes: self.prune_modes,
189 }
190 }
191}
192
193impl Default for MockEthProvider {
194 fn default() -> Self {
195 Self::new()
196 }
197}
198
199#[derive(Debug, Clone)]
201pub struct ExtendedAccount {
202 account: Account,
203 bytecode: Option<Bytecode>,
204 storage: HashMap<StorageKey, StorageValue>,
205}
206
207impl ExtendedAccount {
208 pub fn new(nonce: u64, balance: U256) -> Self {
210 Self {
211 account: Account { nonce, balance, bytecode_hash: None },
212 bytecode: None,
213 storage: Default::default(),
214 }
215 }
216
217 pub fn with_bytecode(mut self, bytecode: Bytes) -> Self {
219 let hash = keccak256(&bytecode);
220 self.account.bytecode_hash = Some(hash);
221 self.bytecode = Some(Bytecode::new_raw(bytecode));
222 self
223 }
224
225 pub fn extend_storage(
228 mut self,
229 storage: impl IntoIterator<Item = (StorageKey, StorageValue)>,
230 ) -> Self {
231 self.storage.extend(storage);
232 self
233 }
234}
235
236impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
237 for MockEthProvider<T, ChainSpec>
238{
239 type DB = DatabaseMock;
240 type Provider = Self;
241 type ProviderRW = Self;
242
243 fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
244 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
245 }
246
247 fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
248 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
249 }
250}
251
252impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
253 for MockEthProvider<T, ChainSpec>
254{
255 type Tx = TxMock;
256
257 fn tx_ref(&self) -> &Self::Tx {
258 &self.tx
259 }
260
261 fn tx_mut(&mut self) -> &mut Self::Tx {
262 &mut self.tx
263 }
264
265 fn into_tx(self) -> Self::Tx {
266 self.tx
267 }
268
269 fn commit(self) -> ProviderResult<()> {
270 Ok(self.tx.commit()?)
271 }
272
273 fn prune_modes_ref(&self) -> &PruneModes {
274 &self.prune_modes
275 }
276}
277
278impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
279 for MockEthProvider<T, ChainSpec>
280{
281 type Header = <T::Block as Block>::Header;
282
283 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
284 let lock = self.headers.lock();
285 Ok(lock.get(&block_hash).cloned())
286 }
287
288 fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
289 let lock = self.headers.lock();
290 Ok(lock.values().find(|h| h.number() == num).cloned())
291 }
292
293 fn headers_range(
294 &self,
295 range: impl RangeBounds<BlockNumber>,
296 ) -> ProviderResult<Vec<Self::Header>> {
297 let lock = self.headers.lock();
298
299 let mut headers: Vec<_> =
300 lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
301 headers.sort_by_key(|header| header.number());
302
303 Ok(headers)
304 }
305
306 fn sealed_header(
307 &self,
308 number: BlockNumber,
309 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
310 Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
311 }
312
313 fn sealed_headers_while(
314 &self,
315 range: impl RangeBounds<BlockNumber>,
316 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
317 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
318 Ok(self
319 .headers_range(range)?
320 .into_iter()
321 .map(SealedHeader::seal_slow)
322 .take_while(|h| predicate(h))
323 .collect())
324 }
325}
326
327impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
328where
329 T: NodePrimitives,
330 ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
331{
332 type ChainSpec = ChainSpec;
333
334 fn chain_spec(&self) -> Arc<Self::ChainSpec> {
335 self.chain_spec.clone()
336 }
337}
338
339impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
340 for MockEthProvider<T, ChainSpec>
341{
342 type Transaction = T::SignedTx;
343
344 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
345 let lock = self.blocks.lock();
346 let tx_number = lock
347 .values()
348 .flat_map(|block| block.body().transactions())
349 .position(|tx| *tx.tx_hash() == tx_hash)
350 .map(|pos| pos as TxNumber);
351
352 Ok(tx_number)
353 }
354
355 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
356 let lock = self.blocks.lock();
357 let transaction =
358 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
359
360 Ok(transaction)
361 }
362
363 fn transaction_by_id_unhashed(
364 &self,
365 id: TxNumber,
366 ) -> ProviderResult<Option<Self::Transaction>> {
367 let lock = self.blocks.lock();
368 let transaction =
369 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
370
371 Ok(transaction)
372 }
373
374 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
375 Ok(self.blocks.lock().iter().find_map(|(_, block)| {
376 block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
377 }))
378 }
379
380 fn transaction_by_hash_with_meta(
381 &self,
382 hash: TxHash,
383 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
384 let lock = self.blocks.lock();
385 for (block_hash, block) in lock.iter() {
386 for (index, tx) in block.body().transactions_iter().enumerate() {
387 if *tx.tx_hash() == hash {
388 let meta = TransactionMeta {
389 tx_hash: hash,
390 index: index as u64,
391 block_hash: *block_hash,
392 block_number: block.header().number(),
393 base_fee: block.header().base_fee_per_gas(),
394 excess_blob_gas: block.header().excess_blob_gas(),
395 timestamp: block.header().timestamp(),
396 };
397 return Ok(Some((tx.clone(), meta)))
398 }
399 }
400 }
401 Ok(None)
402 }
403
404 fn transactions_by_block(
405 &self,
406 id: BlockHashOrNumber,
407 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
408 Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
409 }
410
411 fn transactions_by_block_range(
412 &self,
413 range: impl RangeBounds<alloy_primitives::BlockNumber>,
414 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
415 let mut map = BTreeMap::new();
417 for (_, block) in self.blocks.lock().iter() {
418 if range.contains(&block.header().number()) {
419 map.insert(block.header().number(), block.body().clone_transactions());
420 }
421 }
422
423 Ok(map.into_values().collect())
424 }
425
426 fn transactions_by_tx_range(
427 &self,
428 range: impl RangeBounds<TxNumber>,
429 ) -> ProviderResult<Vec<Self::Transaction>> {
430 let lock = self.blocks.lock();
431 let transactions = lock
432 .values()
433 .flat_map(|block| block.body().transactions())
434 .enumerate()
435 .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
436 .map(|(_, tx)| tx.clone())
437 .collect();
438
439 Ok(transactions)
440 }
441
442 fn senders_by_tx_range(
443 &self,
444 range: impl RangeBounds<TxNumber>,
445 ) -> ProviderResult<Vec<Address>> {
446 let lock = self.blocks.lock();
447 let transactions = lock
448 .values()
449 .flat_map(|block| block.body().transactions())
450 .enumerate()
451 .filter_map(|(tx_number, tx)| {
452 if range.contains(&(tx_number as TxNumber)) {
453 tx.recover_signer().ok()
454 } else {
455 None
456 }
457 })
458 .collect();
459
460 Ok(transactions)
461 }
462
463 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
464 self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
465 }
466}
467
468impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
469where
470 T: NodePrimitives,
471 ChainSpec: Send + Sync + 'static,
472{
473 type Receipt = T::Receipt;
474
475 fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
476 Ok(None)
477 }
478
479 fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
480 Ok(None)
481 }
482
483 fn receipts_by_block(
484 &self,
485 block: BlockHashOrNumber,
486 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
487 let receipts_lock = self.receipts.lock();
488
489 match block {
490 BlockHashOrNumber::Hash(hash) => {
491 let headers_lock = self.headers.lock();
493 if let Some(header) = headers_lock.get(&hash) {
494 Ok(receipts_lock.get(&header.number()).cloned())
495 } else {
496 Ok(None)
497 }
498 }
499 BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
500 }
501 }
502
503 fn receipts_by_tx_range(
504 &self,
505 _range: impl RangeBounds<TxNumber>,
506 ) -> ProviderResult<Vec<Self::Receipt>> {
507 Ok(vec![])
508 }
509
510 fn receipts_by_block_range(
511 &self,
512 block_range: RangeInclusive<BlockNumber>,
513 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
514 let receipts_lock = self.receipts.lock();
515 let headers_lock = self.headers.lock();
516
517 let mut result = Vec::new();
518 for block_number in block_range {
519 if headers_lock.values().any(|header| header.number() == block_number) {
521 if let Some(block_receipts) = receipts_lock.get(&block_number) {
522 result.push(block_receipts.clone());
523 } else {
524 result.push(vec![]);
526 }
527 }
528 }
529
530 Ok(result)
531 }
532}
533
534impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
535where
536 T: NodePrimitives,
537 Self: ReceiptProvider + BlockIdReader,
538{
539}
540
541impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
542 for MockEthProvider<T, ChainSpec>
543{
544 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
545 let lock = self.headers.lock();
546 let hash =
547 lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
548 Ok(hash)
549 }
550
551 fn canonical_hashes_range(
552 &self,
553 start: BlockNumber,
554 end: BlockNumber,
555 ) -> ProviderResult<Vec<B256>> {
556 let lock = self.headers.lock();
557 let mut hashes: Vec<_> =
558 lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
559
560 hashes.sort_by_key(|(_, header)| header.number());
561
562 Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
563 }
564}
565
566impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
567 for MockEthProvider<T, ChainSpec>
568{
569 fn chain_info(&self) -> ProviderResult<ChainInfo> {
570 let best_block_number = self.best_block_number()?;
571 let lock = self.headers.lock();
572
573 Ok(lock
574 .iter()
575 .find(|(_, header)| header.number() == best_block_number)
576 .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
577 .unwrap_or_default())
578 }
579
580 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
581 let lock = self.headers.lock();
582 lock.iter()
583 .max_by_key(|h| h.1.number())
584 .map(|(_, header)| header.number())
585 .ok_or(ProviderError::BestBlockNotFound)
586 }
587
588 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
589 self.best_block_number()
590 }
591
592 fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
593 let lock = self.headers.lock();
594 Ok(lock.get(&hash).map(|header| header.number()))
595 }
596}
597
598impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
599 for MockEthProvider<T, ChainSpec>
600{
601 fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
602 Ok(None)
603 }
604
605 fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
606 Ok(None)
607 }
608
609 fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
610 Ok(None)
611 }
612}
613
614impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
616 for MockEthProvider<T, ChainSpec>
617{
618 type Block = T::Block;
619
620 fn find_block_by_hash(
621 &self,
622 hash: B256,
623 _source: BlockSource,
624 ) -> ProviderResult<Option<Self::Block>> {
625 self.block(hash.into())
626 }
627
628 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
629 let lock = self.blocks.lock();
630 match id {
631 BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
632 BlockHashOrNumber::Number(num) => {
633 Ok(lock.values().find(|b| b.header().number() == num).cloned())
634 }
635 }
636 }
637
638 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
639 Ok(None)
640 }
641
642 fn pending_block_and_receipts(
643 &self,
644 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<T::Receipt>)>> {
645 Ok(None)
646 }
647
648 fn recovered_block(
649 &self,
650 _id: BlockHashOrNumber,
651 _transaction_kind: TransactionVariant,
652 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
653 Ok(None)
654 }
655
656 fn sealed_block_with_senders(
657 &self,
658 _id: BlockHashOrNumber,
659 _transaction_kind: TransactionVariant,
660 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
661 Ok(None)
662 }
663
664 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
665 let lock = self.blocks.lock();
666
667 let mut blocks: Vec<_> = lock
668 .values()
669 .filter(|block| range.contains(&block.header().number()))
670 .cloned()
671 .collect();
672 blocks.sort_by_key(|block| block.header().number());
673
674 Ok(blocks)
675 }
676
677 fn block_with_senders_range(
678 &self,
679 _range: RangeInclusive<BlockNumber>,
680 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
681 Ok(vec![])
682 }
683
684 fn recovered_block_range(
685 &self,
686 _range: RangeInclusive<BlockNumber>,
687 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
688 Ok(vec![])
689 }
690
691 fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
692 Ok(None)
693 }
694}
695
696impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
697where
698 ChainSpec: EthChainSpec + Send + Sync + 'static,
699 T: NodePrimitives,
700{
701 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
702 match id {
703 BlockId::Number(num) => self.block_by_number_or_tag(num),
704 BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
705 }
706 }
707
708 fn sealed_header_by_id(
709 &self,
710 id: BlockId,
711 ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
712 self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
713 }
714
715 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
716 match self.block_by_id(id)? {
717 None => Ok(None),
718 Some(block) => Ok(Some(block.into_header())),
719 }
720 }
721}
722
723impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
724 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
725 Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
726 }
727}
728
729impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
730 for MockEthProvider<T, ChainSpec>
731{
732 fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
733 Ok(None)
734 }
735
736 fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
737 Ok(None)
738 }
739
740 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
741 Ok(vec![])
742 }
743}
744
745impl<T: NodePrimitives, ChainSpec: Send + Sync> PruneCheckpointReader
746 for MockEthProvider<T, ChainSpec>
747{
748 fn get_prune_checkpoint(
749 &self,
750 _segment: PruneSegment,
751 ) -> ProviderResult<Option<PruneCheckpoint>> {
752 Ok(None)
753 }
754
755 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
756 Ok(vec![])
757 }
758}
759
760impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
761where
762 T: NodePrimitives,
763 ChainSpec: Send + Sync,
764{
765 fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
766 Ok(self.state_roots.lock().pop().unwrap_or_default())
767 }
768
769 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
770 Ok(self.state_roots.lock().pop().unwrap_or_default())
771 }
772
773 fn state_root_with_updates(
774 &self,
775 _state: HashedPostState,
776 ) -> ProviderResult<(B256, TrieUpdates)> {
777 let state_root = self.state_roots.lock().pop().unwrap_or_default();
778 Ok((state_root, Default::default()))
779 }
780
781 fn state_root_from_nodes_with_updates(
782 &self,
783 _input: TrieInput,
784 ) -> ProviderResult<(B256, TrieUpdates)> {
785 let state_root = self.state_roots.lock().pop().unwrap_or_default();
786 Ok((state_root, Default::default()))
787 }
788}
789
790impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
791where
792 T: NodePrimitives,
793 ChainSpec: Send + Sync,
794{
795 fn storage_root(
796 &self,
797 _address: Address,
798 _hashed_storage: HashedStorage,
799 ) -> ProviderResult<B256> {
800 Ok(EMPTY_ROOT_HASH)
801 }
802
803 fn storage_proof(
804 &self,
805 _address: Address,
806 slot: B256,
807 _hashed_storage: HashedStorage,
808 ) -> ProviderResult<reth_trie::StorageProof> {
809 Ok(StorageProof::new(slot))
810 }
811
812 fn storage_multiproof(
813 &self,
814 _address: Address,
815 _slots: &[B256],
816 _hashed_storage: HashedStorage,
817 ) -> ProviderResult<StorageMultiProof> {
818 Ok(StorageMultiProof::empty())
819 }
820}
821
822impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
823where
824 T: NodePrimitives,
825 ChainSpec: Send + Sync,
826{
827 fn proof(
828 &self,
829 _input: TrieInput,
830 address: Address,
831 _slots: &[B256],
832 ) -> ProviderResult<AccountProof> {
833 Ok(AccountProof::new(address))
834 }
835
836 fn multiproof(
837 &self,
838 _input: TrieInput,
839 _targets: MultiProofTargets,
840 ) -> ProviderResult<MultiProof> {
841 Ok(MultiProof::default())
842 }
843
844 fn witness(&self, _input: TrieInput, _target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
845 Ok(Vec::default())
846 }
847}
848
849impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
850 for MockEthProvider<T, ChainSpec>
851{
852 fn hashed_post_state(&self, _state: &revm_database::BundleState) -> HashedPostState {
853 HashedPostState::default()
854 }
855}
856
857impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
858where
859 T: NodePrimitives,
860 ChainSpec: EthChainSpec + Send + Sync + 'static,
861{
862 fn storage(
863 &self,
864 account: Address,
865 storage_key: StorageKey,
866 ) -> ProviderResult<Option<StorageValue>> {
867 let lock = self.accounts.lock();
868 Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
869 }
870}
871
872impl<T, ChainSpec> BytecodeReader for MockEthProvider<T, ChainSpec>
873where
874 T: NodePrimitives,
875 ChainSpec: Send + Sync,
876{
877 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
878 let lock = self.accounts.lock();
879 Ok(lock.values().find_map(|account| {
880 match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
881 (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
882 Some(bytecode.clone())
883 }
884 _ => None,
885 }
886 }))
887 }
888}
889
890impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
891 for MockEthProvider<T, ChainSpec>
892{
893 fn latest(&self) -> ProviderResult<StateProviderBox> {
894 Ok(Box::new(self.clone()))
895 }
896
897 fn state_by_block_number_or_tag(
898 &self,
899 number_or_tag: BlockNumberOrTag,
900 ) -> ProviderResult<StateProviderBox> {
901 match number_or_tag {
902 BlockNumberOrTag::Latest => self.latest(),
903 BlockNumberOrTag::Finalized => {
904 let hash =
906 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
907
908 self.history_by_block_hash(hash)
910 }
911 BlockNumberOrTag::Safe => {
912 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
914
915 self.history_by_block_hash(hash)
916 }
917 BlockNumberOrTag::Earliest => {
918 self.history_by_block_number(self.earliest_block_number()?)
919 }
920 BlockNumberOrTag::Pending => self.pending(),
921 BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
922 }
923 }
924
925 fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
926 Ok(Box::new(self.clone()))
927 }
928
929 fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
930 Ok(Box::new(self.clone()))
931 }
932
933 fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
934 Ok(Box::new(self.clone()))
935 }
936
937 fn pending(&self) -> ProviderResult<StateProviderBox> {
938 Ok(Box::new(self.clone()))
939 }
940
941 fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
942 Ok(Some(Box::new(self.clone())))
943 }
944
945 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
946 Ok(Some(Box::new(self.clone())))
947 }
948}
949
950impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
951 for MockEthProvider<T, ChainSpec>
952{
953 fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
954 Ok(self.block_body_indices.lock().get(&num).copied())
955 }
956 fn block_body_indices_range(
957 &self,
958 _range: RangeInclusive<BlockNumber>,
959 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
960 Ok(vec![])
961 }
962}
963
964impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
965 fn account_block_changeset(
966 &self,
967 _block_number: BlockNumber,
968 ) -> ProviderResult<Vec<AccountBeforeTx>> {
969 Ok(Vec::default())
970 }
971
972 fn get_account_before_block(
973 &self,
974 _block_number: BlockNumber,
975 _address: Address,
976 ) -> ProviderResult<Option<AccountBeforeTx>> {
977 Ok(None)
978 }
979
980 fn account_changesets_range(
981 &self,
982 _range: impl core::ops::RangeBounds<BlockNumber>,
983 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
984 Ok(Vec::default())
985 }
986
987 fn account_changeset_count(&self) -> ProviderResult<usize> {
988 Ok(0)
989 }
990}
991
992impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageChangeSetReader
993 for MockEthProvider<T, ChainSpec>
994{
995 fn storage_changeset(
996 &self,
997 _block_number: BlockNumber,
998 ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
999 Ok(Vec::default())
1000 }
1001
1002 fn get_storage_before_block(
1003 &self,
1004 _block_number: BlockNumber,
1005 _address: Address,
1006 _storage_key: B256,
1007 ) -> ProviderResult<Option<StorageEntry>> {
1008 Ok(None)
1009 }
1010
1011 fn storage_changesets_range(
1012 &self,
1013 _range: RangeInclusive<BlockNumber>,
1014 ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1015 Ok(Vec::default())
1016 }
1017
1018 fn storage_changeset_count(&self) -> ProviderResult<usize> {
1019 Ok(0)
1020 }
1021}
1022
1023impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
1024 type Receipt = T::Receipt;
1025
1026 fn get_state(
1027 &self,
1028 _block: BlockNumber,
1029 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1030 Ok(None)
1031 }
1032}
1033
1034impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1035 for MockEthProvider<T, ChainSpec>
1036{
1037 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1038 broadcast::channel(1).1
1039 }
1040}
1041
1042impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1043 for MockEthProvider<T, ChainSpec>
1044{
1045 type Primitives = T;
1046}
1047
1048#[cfg(test)]
1049mod tests {
1050 use super::*;
1051 use alloy_consensus::Header;
1052 use alloy_primitives::BlockHash;
1053 use reth_ethereum_primitives::Receipt;
1054
1055 #[test]
1056 fn test_mock_provider_receipts() {
1057 let provider = MockEthProvider::<EthPrimitives>::new();
1058
1059 let block_hash = BlockHash::random();
1060 let block_number = 1u64;
1061 let header = Header { number: block_number, ..Default::default() };
1062
1063 let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1064 let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1065 let receipts = vec![receipt1, receipt2];
1066
1067 provider.add_header(block_hash, header);
1068 provider.add_receipts(block_number, receipts.clone());
1069
1070 let result = provider.receipts_by_block(block_hash.into()).unwrap();
1071 assert_eq!(result, Some(receipts.clone()));
1072
1073 let result = provider.receipts_by_block(block_number.into()).unwrap();
1074 assert_eq!(result, Some(receipts.clone()));
1075
1076 let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1077 assert_eq!(range_result, vec![receipts]);
1078
1079 let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1080 assert_eq!(non_existent, None);
1081
1082 let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1083 assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1084 }
1085
1086 #[test]
1087 fn test_mock_provider_receipts_multiple_blocks() {
1088 let provider = MockEthProvider::<EthPrimitives>::new();
1089
1090 let block1_hash = BlockHash::random();
1091 let block2_hash = BlockHash::random();
1092 let block1_number = 1u64;
1093 let block2_number = 2u64;
1094
1095 let header1 = Header { number: block1_number, ..Default::default() };
1096 let header2 = Header { number: block2_number, ..Default::default() };
1097
1098 let receipts1 =
1099 vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1100 let receipts2 =
1101 vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1102
1103 provider.add_header(block1_hash, header1);
1104 provider.add_header(block2_hash, header2);
1105 provider.add_receipts(block1_number, receipts1.clone());
1106 provider.add_receipts(block2_number, receipts2.clone());
1107
1108 let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1109 assert_eq!(range_result.len(), 2);
1110 assert_eq!(range_result[0], receipts1);
1111 assert_eq!(range_result[1], receipts2);
1112
1113 let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1114 assert_eq!(partial_range.len(), 1);
1115 assert_eq!(partial_range[0], receipts1);
1116 }
1117}