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