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