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