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