1use crate::{
2 traits::{BlockSource, ReceiptProvider},
3 AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
4 ChainSpecProvider, ChangeSetReader, HeaderProvider, ReceiptProviderIdExt, StateProvider,
5 StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, TransactionVariant,
6 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,
31};
32use reth_prune_types::PruneModes;
33use reth_stages_types::{StageCheckpoint, StageId};
34use reth_storage_api::{
35 BlockBodyIndicesProvider, BytecodeReader, DBProvider, DatabaseProviderFactory,
36 HashedPostStateProvider, NodePrimitivesProvider, StageCheckpointReader, StateProofProvider,
37 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_header(hash, block.header().clone());
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
194impl Default for MockEthProvider {
195 fn default() -> Self {
196 Self::new()
197 }
198}
199
200#[derive(Debug, Clone)]
202pub struct ExtendedAccount {
203 account: Account,
204 bytecode: Option<Bytecode>,
205 storage: HashMap<StorageKey, StorageValue>,
206}
207
208impl ExtendedAccount {
209 pub fn new(nonce: u64, balance: U256) -> Self {
211 Self {
212 account: Account { nonce, balance, bytecode_hash: None },
213 bytecode: None,
214 storage: Default::default(),
215 }
216 }
217
218 pub fn with_bytecode(mut self, bytecode: Bytes) -> Self {
220 let hash = keccak256(&bytecode);
221 self.account.bytecode_hash = Some(hash);
222 self.bytecode = Some(Bytecode::new_raw(bytecode));
223 self
224 }
225
226 pub fn extend_storage(
229 mut self,
230 storage: impl IntoIterator<Item = (StorageKey, StorageValue)>,
231 ) -> Self {
232 self.storage.extend(storage);
233 self
234 }
235}
236
237impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
238 for MockEthProvider<T, ChainSpec>
239{
240 type DB = DatabaseMock;
241 type Provider = Self;
242 type ProviderRW = Self;
243
244 fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
245 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
246 }
247
248 fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
249 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
250 }
251}
252
253impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
254 for MockEthProvider<T, ChainSpec>
255{
256 type Tx = TxMock;
257
258 fn tx_ref(&self) -> &Self::Tx {
259 &self.tx
260 }
261
262 fn tx_mut(&mut self) -> &mut Self::Tx {
263 &mut self.tx
264 }
265
266 fn into_tx(self) -> Self::Tx {
267 self.tx
268 }
269
270 fn commit(self) -> ProviderResult<bool> {
271 Ok(self.tx.commit()?)
272 }
273
274 fn prune_modes_ref(&self) -> &PruneModes {
275 &self.prune_modes
276 }
277}
278
279impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
280 for MockEthProvider<T, ChainSpec>
281{
282 type Header = <T::Block as Block>::Header;
283
284 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
285 let lock = self.headers.lock();
286 Ok(lock.get(&block_hash).cloned())
287 }
288
289 fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
290 let lock = self.headers.lock();
291 Ok(lock.values().find(|h| h.number() == num).cloned())
292 }
293
294 fn header_td(&self, hash: BlockHash) -> ProviderResult<Option<U256>> {
295 let lock = self.headers.lock();
296 Ok(lock.get(&hash).map(|target| {
297 lock.values()
298 .filter(|h| h.number() < target.number())
299 .fold(target.difficulty(), |td, h| td + h.difficulty())
300 }))
301 }
302
303 fn header_td_by_number(&self, number: BlockNumber) -> ProviderResult<Option<U256>> {
304 let lock = self.headers.lock();
305 let sum = lock
306 .values()
307 .filter(|h| h.number() <= number)
308 .fold(U256::ZERO, |td, h| td + h.difficulty());
309 Ok(Some(sum))
310 }
311
312 fn headers_range(
313 &self,
314 range: impl RangeBounds<BlockNumber>,
315 ) -> ProviderResult<Vec<Self::Header>> {
316 let lock = self.headers.lock();
317
318 let mut headers: Vec<_> =
319 lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
320 headers.sort_by_key(|header| header.number());
321
322 Ok(headers)
323 }
324
325 fn sealed_header(
326 &self,
327 number: BlockNumber,
328 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
329 Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
330 }
331
332 fn sealed_headers_while(
333 &self,
334 range: impl RangeBounds<BlockNumber>,
335 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
336 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
337 Ok(self
338 .headers_range(range)?
339 .into_iter()
340 .map(SealedHeader::seal_slow)
341 .take_while(|h| predicate(h))
342 .collect())
343 }
344}
345
346impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
347where
348 T: NodePrimitives,
349 ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
350{
351 type ChainSpec = ChainSpec;
352
353 fn chain_spec(&self) -> Arc<Self::ChainSpec> {
354 self.chain_spec.clone()
355 }
356}
357
358impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
359 for MockEthProvider<T, ChainSpec>
360{
361 type Transaction = T::SignedTx;
362
363 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
364 let lock = self.blocks.lock();
365 let tx_number = lock
366 .values()
367 .flat_map(|block| block.body().transactions())
368 .position(|tx| *tx.tx_hash() == tx_hash)
369 .map(|pos| pos as TxNumber);
370
371 Ok(tx_number)
372 }
373
374 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
375 let lock = self.blocks.lock();
376 let transaction =
377 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
378
379 Ok(transaction)
380 }
381
382 fn transaction_by_id_unhashed(
383 &self,
384 id: TxNumber,
385 ) -> ProviderResult<Option<Self::Transaction>> {
386 let lock = self.blocks.lock();
387 let transaction =
388 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
389
390 Ok(transaction)
391 }
392
393 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
394 Ok(self.blocks.lock().iter().find_map(|(_, block)| {
395 block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
396 }))
397 }
398
399 fn transaction_by_hash_with_meta(
400 &self,
401 hash: TxHash,
402 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
403 let lock = self.blocks.lock();
404 for (block_hash, block) in lock.iter() {
405 for (index, tx) in block.body().transactions_iter().enumerate() {
406 if *tx.tx_hash() == hash {
407 let meta = TransactionMeta {
408 tx_hash: hash,
409 index: index as u64,
410 block_hash: *block_hash,
411 block_number: block.header().number(),
412 base_fee: block.header().base_fee_per_gas(),
413 excess_blob_gas: block.header().excess_blob_gas(),
414 timestamp: block.header().timestamp(),
415 };
416 return Ok(Some((tx.clone(), meta)))
417 }
418 }
419 }
420 Ok(None)
421 }
422
423 fn transaction_block(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
424 let lock = self.blocks.lock();
425 let mut current_tx_number: TxNumber = 0;
426 for block in lock.values() {
427 if current_tx_number + (block.body().transaction_count() as TxNumber) > id {
428 return Ok(Some(block.header().number()))
429 }
430 current_tx_number += block.body().transaction_count() as TxNumber;
431 }
432 Ok(None)
433 }
434
435 fn transactions_by_block(
436 &self,
437 id: BlockHashOrNumber,
438 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
439 Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
440 }
441
442 fn transactions_by_block_range(
443 &self,
444 range: impl RangeBounds<alloy_primitives::BlockNumber>,
445 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
446 let mut map = BTreeMap::new();
448 for (_, block) in self.blocks.lock().iter() {
449 if range.contains(&block.header().number()) {
450 map.insert(block.header().number(), block.body().clone_transactions());
451 }
452 }
453
454 Ok(map.into_values().collect())
455 }
456
457 fn transactions_by_tx_range(
458 &self,
459 range: impl RangeBounds<TxNumber>,
460 ) -> ProviderResult<Vec<Self::Transaction>> {
461 let lock = self.blocks.lock();
462 let transactions = lock
463 .values()
464 .flat_map(|block| block.body().transactions())
465 .enumerate()
466 .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
467 .map(|(_, tx)| tx.clone())
468 .collect();
469
470 Ok(transactions)
471 }
472
473 fn senders_by_tx_range(
474 &self,
475 range: impl RangeBounds<TxNumber>,
476 ) -> ProviderResult<Vec<Address>> {
477 let lock = self.blocks.lock();
478 let transactions = lock
479 .values()
480 .flat_map(|block| block.body().transactions())
481 .enumerate()
482 .filter_map(|(tx_number, tx)| {
483 if range.contains(&(tx_number as TxNumber)) {
484 tx.recover_signer().ok()
485 } else {
486 None
487 }
488 })
489 .collect();
490
491 Ok(transactions)
492 }
493
494 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
495 self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
496 }
497}
498
499impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
500where
501 T: NodePrimitives,
502 ChainSpec: Send + Sync + 'static,
503{
504 type Receipt = T::Receipt;
505
506 fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
507 Ok(None)
508 }
509
510 fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
511 Ok(None)
512 }
513
514 fn receipts_by_block(
515 &self,
516 block: BlockHashOrNumber,
517 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
518 let receipts_lock = self.receipts.lock();
519
520 match block {
521 BlockHashOrNumber::Hash(hash) => {
522 let headers_lock = self.headers.lock();
524 if let Some(header) = headers_lock.get(&hash) {
525 Ok(receipts_lock.get(&header.number()).cloned())
526 } else {
527 Ok(None)
528 }
529 }
530 BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
531 }
532 }
533
534 fn receipts_by_tx_range(
535 &self,
536 _range: impl RangeBounds<TxNumber>,
537 ) -> ProviderResult<Vec<Self::Receipt>> {
538 Ok(vec![])
539 }
540
541 fn receipts_by_block_range(
542 &self,
543 block_range: RangeInclusive<BlockNumber>,
544 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
545 let receipts_lock = self.receipts.lock();
546 let headers_lock = self.headers.lock();
547
548 let mut result = Vec::new();
549 for block_number in block_range {
550 if headers_lock.values().any(|header| header.number() == block_number) {
552 if let Some(block_receipts) = receipts_lock.get(&block_number) {
553 result.push(block_receipts.clone());
554 } else {
555 result.push(vec![]);
557 }
558 }
559 }
560
561 Ok(result)
562 }
563}
564
565impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
566where
567 T: NodePrimitives,
568 Self: ReceiptProvider + BlockIdReader,
569{
570}
571
572impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
573 for MockEthProvider<T, ChainSpec>
574{
575 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
576 let lock = self.headers.lock();
577 let hash =
578 lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
579 Ok(hash)
580 }
581
582 fn canonical_hashes_range(
583 &self,
584 start: BlockNumber,
585 end: BlockNumber,
586 ) -> ProviderResult<Vec<B256>> {
587 let lock = self.headers.lock();
588 let mut hashes: Vec<_> =
589 lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
590
591 hashes.sort_by_key(|(_, header)| header.number());
592
593 Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
594 }
595}
596
597impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
598 for MockEthProvider<T, ChainSpec>
599{
600 fn chain_info(&self) -> ProviderResult<ChainInfo> {
601 let best_block_number = self.best_block_number()?;
602 let lock = self.headers.lock();
603
604 Ok(lock
605 .iter()
606 .find(|(_, header)| header.number() == best_block_number)
607 .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
608 .unwrap_or_default())
609 }
610
611 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
612 let lock = self.headers.lock();
613 lock.iter()
614 .max_by_key(|h| h.1.number())
615 .map(|(_, header)| header.number())
616 .ok_or(ProviderError::BestBlockNotFound)
617 }
618
619 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
620 self.best_block_number()
621 }
622
623 fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
624 let lock = self.headers.lock();
625 Ok(lock.get(&hash).map(|header| header.number()))
626 }
627}
628
629impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
630 for MockEthProvider<T, ChainSpec>
631{
632 fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
633 Ok(None)
634 }
635
636 fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
637 Ok(None)
638 }
639
640 fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
641 Ok(None)
642 }
643}
644
645impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
647 for MockEthProvider<T, ChainSpec>
648{
649 type Block = T::Block;
650
651 fn find_block_by_hash(
652 &self,
653 hash: B256,
654 _source: BlockSource,
655 ) -> ProviderResult<Option<Self::Block>> {
656 self.block(hash.into())
657 }
658
659 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
660 let lock = self.blocks.lock();
661 match id {
662 BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
663 BlockHashOrNumber::Number(num) => {
664 Ok(lock.values().find(|b| b.header().number() == num).cloned())
665 }
666 }
667 }
668
669 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
670 Ok(None)
671 }
672
673 fn pending_block_and_receipts(
674 &self,
675 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<T::Receipt>)>> {
676 Ok(None)
677 }
678
679 fn recovered_block(
680 &self,
681 _id: BlockHashOrNumber,
682 _transaction_kind: TransactionVariant,
683 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
684 Ok(None)
685 }
686
687 fn sealed_block_with_senders(
688 &self,
689 _id: BlockHashOrNumber,
690 _transaction_kind: TransactionVariant,
691 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
692 Ok(None)
693 }
694
695 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
696 let lock = self.blocks.lock();
697
698 let mut blocks: Vec<_> = lock
699 .values()
700 .filter(|block| range.contains(&block.header().number()))
701 .cloned()
702 .collect();
703 blocks.sort_by_key(|block| block.header().number());
704
705 Ok(blocks)
706 }
707
708 fn block_with_senders_range(
709 &self,
710 _range: RangeInclusive<BlockNumber>,
711 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
712 Ok(vec![])
713 }
714
715 fn recovered_block_range(
716 &self,
717 _range: RangeInclusive<BlockNumber>,
718 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
719 Ok(vec![])
720 }
721
722 fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
723 Ok(None)
724 }
725}
726
727impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
728where
729 ChainSpec: EthChainSpec + Send + Sync + 'static,
730 T: NodePrimitives,
731{
732 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
733 match id {
734 BlockId::Number(num) => self.block_by_number_or_tag(num),
735 BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
736 }
737 }
738
739 fn sealed_header_by_id(
740 &self,
741 id: BlockId,
742 ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
743 self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
744 }
745
746 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
747 match self.block_by_id(id)? {
748 None => Ok(None),
749 Some(block) => Ok(Some(block.into_header())),
750 }
751 }
752}
753
754impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
755 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
756 Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
757 }
758}
759
760impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
761 for MockEthProvider<T, ChainSpec>
762{
763 fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
764 Ok(None)
765 }
766
767 fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
768 Ok(None)
769 }
770
771 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
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: EthChainSpec + Send + Sync + 'static> StateProviderFactory
907 for MockEthProvider<T, ChainSpec>
908{
909 fn latest(&self) -> ProviderResult<StateProviderBox> {
910 Ok(Box::new(self.clone()))
911 }
912
913 fn state_by_block_number_or_tag(
914 &self,
915 number_or_tag: BlockNumberOrTag,
916 ) -> ProviderResult<StateProviderBox> {
917 match number_or_tag {
918 BlockNumberOrTag::Latest => self.latest(),
919 BlockNumberOrTag::Finalized => {
920 let hash =
922 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
923
924 self.history_by_block_hash(hash)
926 }
927 BlockNumberOrTag::Safe => {
928 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
930
931 self.history_by_block_hash(hash)
932 }
933 BlockNumberOrTag::Earliest => {
934 self.history_by_block_number(self.earliest_block_number()?)
935 }
936 BlockNumberOrTag::Pending => self.pending(),
937 BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
938 }
939 }
940
941 fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
942 Ok(Box::new(self.clone()))
943 }
944
945 fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
946 Ok(Box::new(self.clone()))
947 }
948
949 fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
950 Ok(Box::new(self.clone()))
951 }
952
953 fn pending(&self) -> ProviderResult<StateProviderBox> {
954 Ok(Box::new(self.clone()))
955 }
956
957 fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
958 Ok(Some(Box::new(self.clone())))
959 }
960
961 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
962 Ok(Some(Box::new(self.clone())))
963 }
964}
965
966impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
967 for MockEthProvider<T, ChainSpec>
968{
969 fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
970 Ok(self.block_body_indices.lock().get(&num).copied())
971 }
972 fn block_body_indices_range(
973 &self,
974 _range: RangeInclusive<BlockNumber>,
975 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
976 Ok(vec![])
977 }
978}
979
980impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
981 fn account_block_changeset(
982 &self,
983 _block_number: BlockNumber,
984 ) -> ProviderResult<Vec<AccountBeforeTx>> {
985 Ok(Vec::default())
986 }
987
988 fn get_account_before_block(
989 &self,
990 _block_number: BlockNumber,
991 _address: Address,
992 ) -> ProviderResult<Option<AccountBeforeTx>> {
993 Ok(None)
994 }
995}
996
997impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
998 type Receipt = T::Receipt;
999
1000 fn get_state(
1001 &self,
1002 _block: BlockNumber,
1003 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1004 Ok(None)
1005 }
1006}
1007
1008impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1009 for MockEthProvider<T, ChainSpec>
1010{
1011 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1012 broadcast::channel(1).1
1013 }
1014}
1015
1016impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1017 for MockEthProvider<T, ChainSpec>
1018{
1019 type Primitives = T;
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use super::*;
1025 use alloy_consensus::Header;
1026 use alloy_primitives::BlockHash;
1027 use reth_ethereum_primitives::Receipt;
1028
1029 #[test]
1030 fn test_mock_provider_receipts() {
1031 let provider = MockEthProvider::<EthPrimitives>::new();
1032
1033 let block_hash = BlockHash::random();
1034 let block_number = 1u64;
1035 let header = Header { number: block_number, ..Default::default() };
1036
1037 let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1038 let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1039 let receipts = vec![receipt1, receipt2];
1040
1041 provider.add_header(block_hash, header);
1042 provider.add_receipts(block_number, receipts.clone());
1043
1044 let result = provider.receipts_by_block(block_hash.into()).unwrap();
1045 assert_eq!(result, Some(receipts.clone()));
1046
1047 let result = provider.receipts_by_block(block_number.into()).unwrap();
1048 assert_eq!(result, Some(receipts.clone()));
1049
1050 let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1051 assert_eq!(range_result, vec![receipts]);
1052
1053 let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1054 assert_eq!(non_existent, None);
1055
1056 let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1057 assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1058 }
1059
1060 #[test]
1061 fn test_mock_provider_receipts_multiple_blocks() {
1062 let provider = MockEthProvider::<EthPrimitives>::new();
1063
1064 let block1_hash = BlockHash::random();
1065 let block2_hash = BlockHash::random();
1066 let block1_number = 1u64;
1067 let block2_number = 2u64;
1068
1069 let header1 = Header { number: block1_number, ..Default::default() };
1070 let header2 = Header { number: block2_number, ..Default::default() };
1071
1072 let receipts1 =
1073 vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1074 let receipts2 =
1075 vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1076
1077 provider.add_header(block1_hash, header1);
1078 provider.add_header(block2_hash, header2);
1079 provider.add_receipts(block1_number, receipts1.clone());
1080 provider.add_receipts(block2_number, receipts2.clone());
1081
1082 let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1083 assert_eq!(range_result.len(), 2);
1084 assert_eq!(range_result[0], receipts1);
1085 assert_eq!(range_result[1], receipts2);
1086
1087 let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1088 assert_eq!(partial_range.len(), 1);
1089 assert_eq!(partial_range[0], receipts1);
1090 }
1091}