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