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,
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 StorageRootProvider, TrieReader,
38};
39use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
40use reth_trie::{
41 updates::{TrieUpdates, TrieUpdatesSorted},
42 AccountProof, HashedPostState, HashedStorage, MultiProof, MultiProofTargets, StorageMultiProof,
43 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<HashMap<B256, T::Block>>>,
59 pub headers: Arc<Mutex<HashMap<B256, <T::Block as Block>::Header>>>,
61 pub receipts: Arc<Mutex<HashMap<BlockNumber, Vec<T::Receipt>>>>,
63 pub accounts: Arc<Mutex<HashMap<Address, 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
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 headers_range(
295 &self,
296 range: impl RangeBounds<BlockNumber>,
297 ) -> ProviderResult<Vec<Self::Header>> {
298 let lock = self.headers.lock();
299
300 let mut headers: Vec<_> =
301 lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
302 headers.sort_by_key(|header| header.number());
303
304 Ok(headers)
305 }
306
307 fn sealed_header(
308 &self,
309 number: BlockNumber,
310 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
311 Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
312 }
313
314 fn sealed_headers_while(
315 &self,
316 range: impl RangeBounds<BlockNumber>,
317 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
318 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
319 Ok(self
320 .headers_range(range)?
321 .into_iter()
322 .map(SealedHeader::seal_slow)
323 .take_while(|h| predicate(h))
324 .collect())
325 }
326}
327
328impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
329where
330 T: NodePrimitives,
331 ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
332{
333 type ChainSpec = ChainSpec;
334
335 fn chain_spec(&self) -> Arc<Self::ChainSpec> {
336 self.chain_spec.clone()
337 }
338}
339
340impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
341 for MockEthProvider<T, ChainSpec>
342{
343 type Transaction = T::SignedTx;
344
345 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
346 let lock = self.blocks.lock();
347 let tx_number = lock
348 .values()
349 .flat_map(|block| block.body().transactions())
350 .position(|tx| *tx.tx_hash() == tx_hash)
351 .map(|pos| pos as TxNumber);
352
353 Ok(tx_number)
354 }
355
356 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
357 let lock = self.blocks.lock();
358 let transaction =
359 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
360
361 Ok(transaction)
362 }
363
364 fn transaction_by_id_unhashed(
365 &self,
366 id: TxNumber,
367 ) -> ProviderResult<Option<Self::Transaction>> {
368 let lock = self.blocks.lock();
369 let transaction =
370 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
371
372 Ok(transaction)
373 }
374
375 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
376 Ok(self.blocks.lock().iter().find_map(|(_, block)| {
377 block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
378 }))
379 }
380
381 fn transaction_by_hash_with_meta(
382 &self,
383 hash: TxHash,
384 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
385 let lock = self.blocks.lock();
386 for (block_hash, block) in lock.iter() {
387 for (index, tx) in block.body().transactions_iter().enumerate() {
388 if *tx.tx_hash() == hash {
389 let meta = TransactionMeta {
390 tx_hash: hash,
391 index: index as u64,
392 block_hash: *block_hash,
393 block_number: block.header().number(),
394 base_fee: block.header().base_fee_per_gas(),
395 excess_blob_gas: block.header().excess_blob_gas(),
396 timestamp: block.header().timestamp(),
397 };
398 return Ok(Some((tx.clone(), meta)))
399 }
400 }
401 }
402 Ok(None)
403 }
404
405 fn transactions_by_block(
406 &self,
407 id: BlockHashOrNumber,
408 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
409 Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
410 }
411
412 fn transactions_by_block_range(
413 &self,
414 range: impl RangeBounds<alloy_primitives::BlockNumber>,
415 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
416 let mut map = BTreeMap::new();
418 for (_, block) in self.blocks.lock().iter() {
419 if range.contains(&block.header().number()) {
420 map.insert(block.header().number(), block.body().clone_transactions());
421 }
422 }
423
424 Ok(map.into_values().collect())
425 }
426
427 fn transactions_by_tx_range(
428 &self,
429 range: impl RangeBounds<TxNumber>,
430 ) -> ProviderResult<Vec<Self::Transaction>> {
431 let lock = self.blocks.lock();
432 let transactions = lock
433 .values()
434 .flat_map(|block| block.body().transactions())
435 .enumerate()
436 .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
437 .map(|(_, tx)| tx.clone())
438 .collect();
439
440 Ok(transactions)
441 }
442
443 fn senders_by_tx_range(
444 &self,
445 range: impl RangeBounds<TxNumber>,
446 ) -> ProviderResult<Vec<Address>> {
447 let lock = self.blocks.lock();
448 let transactions = lock
449 .values()
450 .flat_map(|block| block.body().transactions())
451 .enumerate()
452 .filter_map(|(tx_number, tx)| {
453 if range.contains(&(tx_number as TxNumber)) {
454 tx.recover_signer().ok()
455 } else {
456 None
457 }
458 })
459 .collect();
460
461 Ok(transactions)
462 }
463
464 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
465 self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
466 }
467}
468
469impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
470where
471 T: NodePrimitives,
472 ChainSpec: Send + Sync + 'static,
473{
474 type Receipt = T::Receipt;
475
476 fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
477 Ok(None)
478 }
479
480 fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
481 Ok(None)
482 }
483
484 fn receipts_by_block(
485 &self,
486 block: BlockHashOrNumber,
487 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
488 let receipts_lock = self.receipts.lock();
489
490 match block {
491 BlockHashOrNumber::Hash(hash) => {
492 let headers_lock = self.headers.lock();
494 if let Some(header) = headers_lock.get(&hash) {
495 Ok(receipts_lock.get(&header.number()).cloned())
496 } else {
497 Ok(None)
498 }
499 }
500 BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
501 }
502 }
503
504 fn receipts_by_tx_range(
505 &self,
506 _range: impl RangeBounds<TxNumber>,
507 ) -> ProviderResult<Vec<Self::Receipt>> {
508 Ok(vec![])
509 }
510
511 fn receipts_by_block_range(
512 &self,
513 block_range: RangeInclusive<BlockNumber>,
514 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
515 let receipts_lock = self.receipts.lock();
516 let headers_lock = self.headers.lock();
517
518 let mut result = Vec::new();
519 for block_number in block_range {
520 if headers_lock.values().any(|header| header.number() == block_number) {
522 if let Some(block_receipts) = receipts_lock.get(&block_number) {
523 result.push(block_receipts.clone());
524 } else {
525 result.push(vec![]);
527 }
528 }
529 }
530
531 Ok(result)
532 }
533}
534
535impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
536where
537 T: NodePrimitives,
538 Self: ReceiptProvider + BlockIdReader,
539{
540}
541
542impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
543 for MockEthProvider<T, ChainSpec>
544{
545 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
546 let lock = self.headers.lock();
547 let hash =
548 lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
549 Ok(hash)
550 }
551
552 fn canonical_hashes_range(
553 &self,
554 start: BlockNumber,
555 end: BlockNumber,
556 ) -> ProviderResult<Vec<B256>> {
557 let lock = self.headers.lock();
558 let mut hashes: Vec<_> =
559 lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
560
561 hashes.sort_by_key(|(_, header)| header.number());
562
563 Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
564 }
565}
566
567impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
568 for MockEthProvider<T, ChainSpec>
569{
570 fn chain_info(&self) -> ProviderResult<ChainInfo> {
571 let best_block_number = self.best_block_number()?;
572 let lock = self.headers.lock();
573
574 Ok(lock
575 .iter()
576 .find(|(_, header)| header.number() == best_block_number)
577 .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
578 .unwrap_or_default())
579 }
580
581 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
582 let lock = self.headers.lock();
583 lock.iter()
584 .max_by_key(|h| h.1.number())
585 .map(|(_, header)| header.number())
586 .ok_or(ProviderError::BestBlockNotFound)
587 }
588
589 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
590 self.best_block_number()
591 }
592
593 fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
594 let lock = self.headers.lock();
595 Ok(lock.get(&hash).map(|header| header.number()))
596 }
597}
598
599impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
600 for MockEthProvider<T, ChainSpec>
601{
602 fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
603 Ok(None)
604 }
605
606 fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
607 Ok(None)
608 }
609
610 fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
611 Ok(None)
612 }
613}
614
615impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
617 for MockEthProvider<T, ChainSpec>
618{
619 type Block = T::Block;
620
621 fn find_block_by_hash(
622 &self,
623 hash: B256,
624 _source: BlockSource,
625 ) -> ProviderResult<Option<Self::Block>> {
626 self.block(hash.into())
627 }
628
629 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
630 let lock = self.blocks.lock();
631 match id {
632 BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
633 BlockHashOrNumber::Number(num) => {
634 Ok(lock.values().find(|b| b.header().number() == num).cloned())
635 }
636 }
637 }
638
639 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
640 Ok(None)
641 }
642
643 fn pending_block_and_receipts(
644 &self,
645 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<T::Receipt>)>> {
646 Ok(None)
647 }
648
649 fn recovered_block(
650 &self,
651 _id: BlockHashOrNumber,
652 _transaction_kind: TransactionVariant,
653 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
654 Ok(None)
655 }
656
657 fn sealed_block_with_senders(
658 &self,
659 _id: BlockHashOrNumber,
660 _transaction_kind: TransactionVariant,
661 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
662 Ok(None)
663 }
664
665 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
666 let lock = self.blocks.lock();
667
668 let mut blocks: Vec<_> = lock
669 .values()
670 .filter(|block| range.contains(&block.header().number()))
671 .cloned()
672 .collect();
673 blocks.sort_by_key(|block| block.header().number());
674
675 Ok(blocks)
676 }
677
678 fn block_with_senders_range(
679 &self,
680 _range: RangeInclusive<BlockNumber>,
681 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
682 Ok(vec![])
683 }
684
685 fn recovered_block_range(
686 &self,
687 _range: RangeInclusive<BlockNumber>,
688 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
689 Ok(vec![])
690 }
691
692 fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
693 Ok(None)
694 }
695}
696
697impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
698where
699 ChainSpec: EthChainSpec + Send + Sync + 'static,
700 T: NodePrimitives,
701{
702 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
703 match id {
704 BlockId::Number(num) => self.block_by_number_or_tag(num),
705 BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
706 }
707 }
708
709 fn sealed_header_by_id(
710 &self,
711 id: BlockId,
712 ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
713 self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
714 }
715
716 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
717 match self.block_by_id(id)? {
718 None => Ok(None),
719 Some(block) => Ok(Some(block.into_header())),
720 }
721 }
722}
723
724impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
725 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
726 Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
727 }
728}
729
730impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
731 for MockEthProvider<T, ChainSpec>
732{
733 fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
734 Ok(None)
735 }
736
737 fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
738 Ok(None)
739 }
740
741 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
742 Ok(vec![])
743 }
744}
745
746impl<T: NodePrimitives, ChainSpec: Send + Sync> PruneCheckpointReader
747 for MockEthProvider<T, ChainSpec>
748{
749 fn get_prune_checkpoint(
750 &self,
751 _segment: PruneSegment,
752 ) -> ProviderResult<Option<PruneCheckpoint>> {
753 Ok(None)
754 }
755
756 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
757 Ok(vec![])
758 }
759}
760
761impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
762where
763 T: NodePrimitives,
764 ChainSpec: Send + Sync,
765{
766 fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
767 Ok(self.state_roots.lock().pop().unwrap_or_default())
768 }
769
770 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
771 Ok(self.state_roots.lock().pop().unwrap_or_default())
772 }
773
774 fn state_root_with_updates(
775 &self,
776 _state: HashedPostState,
777 ) -> ProviderResult<(B256, TrieUpdates)> {
778 let state_root = self.state_roots.lock().pop().unwrap_or_default();
779 Ok((state_root, Default::default()))
780 }
781
782 fn state_root_from_nodes_with_updates(
783 &self,
784 _input: TrieInput,
785 ) -> ProviderResult<(B256, TrieUpdates)> {
786 let state_root = self.state_roots.lock().pop().unwrap_or_default();
787 Ok((state_root, Default::default()))
788 }
789}
790
791impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
792where
793 T: NodePrimitives,
794 ChainSpec: Send + Sync,
795{
796 fn storage_root(
797 &self,
798 _address: Address,
799 _hashed_storage: HashedStorage,
800 ) -> ProviderResult<B256> {
801 Ok(EMPTY_ROOT_HASH)
802 }
803
804 fn storage_proof(
805 &self,
806 _address: Address,
807 slot: B256,
808 _hashed_storage: HashedStorage,
809 ) -> ProviderResult<reth_trie::StorageProof> {
810 Ok(StorageProof::new(slot))
811 }
812
813 fn storage_multiproof(
814 &self,
815 _address: Address,
816 _slots: &[B256],
817 _hashed_storage: HashedStorage,
818 ) -> ProviderResult<StorageMultiProof> {
819 Ok(StorageMultiProof::empty())
820 }
821}
822
823impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
824where
825 T: NodePrimitives,
826 ChainSpec: Send + Sync,
827{
828 fn proof(
829 &self,
830 _input: TrieInput,
831 address: Address,
832 _slots: &[B256],
833 ) -> ProviderResult<AccountProof> {
834 Ok(AccountProof::new(address))
835 }
836
837 fn multiproof(
838 &self,
839 _input: TrieInput,
840 _targets: MultiProofTargets,
841 ) -> ProviderResult<MultiProof> {
842 Ok(MultiProof::default())
843 }
844
845 fn witness(&self, _input: TrieInput, _target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
846 Ok(Vec::default())
847 }
848}
849
850impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
851 for MockEthProvider<T, ChainSpec>
852{
853 fn hashed_post_state(&self, _state: &revm_database::BundleState) -> HashedPostState {
854 HashedPostState::default()
855 }
856}
857
858impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
859where
860 T: NodePrimitives,
861 ChainSpec: EthChainSpec + Send + Sync + 'static,
862{
863 fn storage(
864 &self,
865 account: Address,
866 storage_key: StorageKey,
867 ) -> ProviderResult<Option<StorageValue>> {
868 let lock = self.accounts.lock();
869 Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
870 }
871}
872
873impl<T, ChainSpec> BytecodeReader for MockEthProvider<T, ChainSpec>
874where
875 T: NodePrimitives,
876 ChainSpec: Send + Sync,
877{
878 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
879 let lock = self.accounts.lock();
880 Ok(lock.values().find_map(|account| {
881 match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
882 (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
883 Some(bytecode.clone())
884 }
885 _ => None,
886 }
887 }))
888 }
889}
890
891impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
892 for MockEthProvider<T, ChainSpec>
893{
894 fn latest(&self) -> ProviderResult<StateProviderBox> {
895 Ok(Box::new(self.clone()))
896 }
897
898 fn state_by_block_number_or_tag(
899 &self,
900 number_or_tag: BlockNumberOrTag,
901 ) -> ProviderResult<StateProviderBox> {
902 match number_or_tag {
903 BlockNumberOrTag::Latest => self.latest(),
904 BlockNumberOrTag::Finalized => {
905 let hash =
907 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
908
909 self.history_by_block_hash(hash)
911 }
912 BlockNumberOrTag::Safe => {
913 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
915
916 self.history_by_block_hash(hash)
917 }
918 BlockNumberOrTag::Earliest => {
919 self.history_by_block_number(self.earliest_block_number()?)
920 }
921 BlockNumberOrTag::Pending => self.pending(),
922 BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
923 }
924 }
925
926 fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
927 Ok(Box::new(self.clone()))
928 }
929
930 fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
931 Ok(Box::new(self.clone()))
932 }
933
934 fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
935 Ok(Box::new(self.clone()))
936 }
937
938 fn pending(&self) -> ProviderResult<StateProviderBox> {
939 Ok(Box::new(self.clone()))
940 }
941
942 fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
943 Ok(Some(Box::new(self.clone())))
944 }
945
946 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
947 Ok(Some(Box::new(self.clone())))
948 }
949}
950
951impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
952 for MockEthProvider<T, ChainSpec>
953{
954 fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
955 Ok(self.block_body_indices.lock().get(&num).copied())
956 }
957 fn block_body_indices_range(
958 &self,
959 _range: RangeInclusive<BlockNumber>,
960 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
961 Ok(vec![])
962 }
963}
964
965impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
966 fn account_block_changeset(
967 &self,
968 _block_number: BlockNumber,
969 ) -> ProviderResult<Vec<AccountBeforeTx>> {
970 Ok(Vec::default())
971 }
972
973 fn get_account_before_block(
974 &self,
975 _block_number: BlockNumber,
976 _address: Address,
977 ) -> ProviderResult<Option<AccountBeforeTx>> {
978 Ok(None)
979 }
980}
981
982impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
983 type Receipt = T::Receipt;
984
985 fn get_state(
986 &self,
987 _block: BlockNumber,
988 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
989 Ok(None)
990 }
991}
992
993impl<T: NodePrimitives, ChainSpec: Send + Sync> TrieReader for MockEthProvider<T, ChainSpec> {
994 fn trie_reverts(&self, _from: BlockNumber) -> ProviderResult<TrieUpdatesSorted> {
995 Ok(TrieUpdatesSorted::default())
996 }
997
998 fn get_block_trie_updates(
999 &self,
1000 _block_number: BlockNumber,
1001 ) -> ProviderResult<TrieUpdatesSorted> {
1002 Ok(TrieUpdatesSorted::default())
1003 }
1004}
1005
1006impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1007 for MockEthProvider<T, ChainSpec>
1008{
1009 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1010 broadcast::channel(1).1
1011 }
1012}
1013
1014impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1015 for MockEthProvider<T, ChainSpec>
1016{
1017 type Primitives = T;
1018}
1019
1020#[cfg(test)]
1021mod tests {
1022 use super::*;
1023 use alloy_consensus::Header;
1024 use alloy_primitives::BlockHash;
1025 use reth_ethereum_primitives::Receipt;
1026
1027 #[test]
1028 fn test_mock_provider_receipts() {
1029 let provider = MockEthProvider::<EthPrimitives>::new();
1030
1031 let block_hash = BlockHash::random();
1032 let block_number = 1u64;
1033 let header = Header { number: block_number, ..Default::default() };
1034
1035 let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1036 let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1037 let receipts = vec![receipt1, receipt2];
1038
1039 provider.add_header(block_hash, header);
1040 provider.add_receipts(block_number, receipts.clone());
1041
1042 let result = provider.receipts_by_block(block_hash.into()).unwrap();
1043 assert_eq!(result, Some(receipts.clone()));
1044
1045 let result = provider.receipts_by_block(block_number.into()).unwrap();
1046 assert_eq!(result, Some(receipts.clone()));
1047
1048 let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1049 assert_eq!(range_result, vec![receipts]);
1050
1051 let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1052 assert_eq!(non_existent, None);
1053
1054 let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1055 assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1056 }
1057
1058 #[test]
1059 fn test_mock_provider_receipts_multiple_blocks() {
1060 let provider = MockEthProvider::<EthPrimitives>::new();
1061
1062 let block1_hash = BlockHash::random();
1063 let block2_hash = BlockHash::random();
1064 let block1_number = 1u64;
1065 let block2_number = 2u64;
1066
1067 let header1 = Header { number: block1_number, ..Default::default() };
1068 let header2 = Header { number: block2_number, ..Default::default() };
1069
1070 let receipts1 =
1071 vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1072 let receipts2 =
1073 vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1074
1075 provider.add_header(block1_hash, header1);
1076 provider.add_header(block2_hash, header2);
1077 provider.add_receipts(block1_number, receipts1.clone());
1078 provider.add_receipts(block2_number, receipts2.clone());
1079
1080 let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1081 assert_eq!(range_result.len(), 2);
1082 assert_eq!(range_result[0], receipts1);
1083 assert_eq!(range_result[1], receipts2);
1084
1085 let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1086 assert_eq!(partial_range.len(), 1);
1087 assert_eq!(partial_range[0], receipts1);
1088 }
1089}