1use crate::{
2 traits::{BlockSource, ReceiptProvider},
3 AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
4 BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, HeaderProvider,
5 PruneCheckpointReader, RangeEnd, RangeResponse, RangeResult, ReceiptProviderIdExt,
6 StateProvider, StateProviderBox, StateProviderFactory, StateRangeProvider,
7 StateRangeProviderFactory, StateRangeView, StateReader, StateRootProvider, StorageRangeResult,
8 TransactionVariant, TransactionsProvider,
9};
10use alloy_consensus::{
11 constants::EMPTY_ROOT_HASH,
12 transaction::{TransactionMeta, TxHashRef},
13 BlockHeader,
14};
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag};
16use alloy_primitives::{
17 keccak256,
18 map::{AddressMap, B256Map, HashMap},
19 Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, TxNumber, B256, U256,
20};
21use parking_lot::Mutex;
22use reth_chain_state::{CanonStateNotifications, CanonStateSubscriptions};
23use reth_chainspec::{ChainInfo, EthChainSpec};
24use reth_db::transaction::DbTx;
25use reth_db_api::{
26 mock::{DatabaseMock, TxMock},
27 models::{AccountBeforeTx, StorageSettings, StoredBlockBodyIndices},
28};
29use reth_ethereum_primitives::EthPrimitives;
30use reth_execution_types::ExecutionOutcome;
31use reth_primitives_traits::{
32 Account, Block, BlockBody, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedHeader,
33 SignerRecoverable, StorageEntry,
34};
35use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
36use reth_stages_types::{StageCheckpoint, StageId};
37use reth_storage_api::{
38 BlockBodyIndicesProvider, BytecodeReader, DBProvider, DatabaseProviderFactory,
39 HashedPostStateProvider, NodePrimitivesProvider, StageCheckpointReader, StateProofProvider,
40 StorageChangeSetReader, StorageRootProvider, StorageSettingsCache,
41};
42use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
43use reth_trie::{
44 updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
45 MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
46};
47use std::{
48 collections::{BTreeMap, VecDeque},
49 fmt::Debug,
50 ops::{RangeBounds, RangeInclusive},
51 sync::{
52 atomic::{AtomicBool, AtomicUsize, Ordering},
53 Arc,
54 },
55};
56use tokio::sync::broadcast;
57
58#[derive(Debug)]
60pub struct MockEthProvider<T: NodePrimitives = EthPrimitives, ChainSpec = reth_chainspec::ChainSpec>
61{
62 pub blocks: Arc<Mutex<B256Map<T::Block>>>,
64 pub headers: Arc<Mutex<B256Map<<T::Block as Block>::Header>>>,
66 pub receipts: Arc<Mutex<HashMap<BlockNumber, Vec<T::Receipt>>>>,
68 pub accounts: Arc<Mutex<AddressMap<ExtendedAccount>>>,
70 pub chain_spec: Arc<ChainSpec>,
72 pub state_roots: Arc<Mutex<Vec<B256>>>,
74 pub block_body_indices: Arc<Mutex<HashMap<BlockNumber, StoredBlockBodyIndices>>>,
76 pub bal_store: BalStoreHandle,
78 snap_state_reads_fail: Arc<AtomicBool>,
80 snap_state_range_available: Arc<AtomicBool>,
82 snap_state_range_resolutions: Arc<AtomicUsize>,
84 snap_account_range: Arc<Mutex<MockAccountRange>>,
86 snap_storage_roots: Arc<Mutex<B256Map<B256>>>,
88 snap_storage_ranges: Arc<Mutex<VecDeque<MockStorageRangeOutcome>>>,
90 snap_storage_range_requests: Arc<Mutex<Vec<MockStorageRangeRequest>>>,
92 snap_account_proof: Arc<Mutex<Option<Vec<Bytes>>>>,
94 snap_storage_proof: Arc<Mutex<Option<Vec<Bytes>>>>,
96 tx: TxMock,
97 prune_modes: Arc<PruneModes>,
98}
99
100type MockAccountRange = Option<(Vec<(B256, Account)>, RangeEnd)>;
102#[derive(Debug, Clone)]
104enum MockStorageRangeOutcome {
105 Error,
107 AccountMissing,
109 Found(Vec<(B256, U256)>, RangeEnd),
111}
112type MockStorageRangeRequest = (B256, B256, B256, usize);
114
115impl<T: NodePrimitives, ChainSpec> Clone for MockEthProvider<T, ChainSpec>
116where
117 T::Block: Clone,
118{
119 fn clone(&self) -> Self {
120 Self {
121 blocks: self.blocks.clone(),
122 headers: self.headers.clone(),
123 receipts: self.receipts.clone(),
124 accounts: self.accounts.clone(),
125 chain_spec: self.chain_spec.clone(),
126 state_roots: self.state_roots.clone(),
127 block_body_indices: self.block_body_indices.clone(),
128 bal_store: self.bal_store.clone(),
129 snap_state_reads_fail: self.snap_state_reads_fail.clone(),
130 snap_state_range_available: self.snap_state_range_available.clone(),
131 snap_state_range_resolutions: self.snap_state_range_resolutions.clone(),
132 snap_account_range: self.snap_account_range.clone(),
133 snap_storage_roots: self.snap_storage_roots.clone(),
134 snap_storage_ranges: self.snap_storage_ranges.clone(),
135 snap_storage_range_requests: self.snap_storage_range_requests.clone(),
136 snap_account_proof: self.snap_account_proof.clone(),
137 snap_storage_proof: self.snap_storage_proof.clone(),
138 tx: self.tx.clone(),
139 prune_modes: self.prune_modes.clone(),
140 }
141 }
142}
143
144impl<T: NodePrimitives> MockEthProvider<T, reth_chainspec::ChainSpec> {
145 pub fn new() -> Self {
147 Self {
148 blocks: Default::default(),
149 headers: Default::default(),
150 receipts: Default::default(),
151 accounts: Default::default(),
152 chain_spec: Arc::new(reth_chainspec::ChainSpecBuilder::mainnet().build()),
153 state_roots: Default::default(),
154 block_body_indices: Default::default(),
155 bal_store: Default::default(),
156 snap_state_reads_fail: Default::default(),
157 snap_state_range_available: Default::default(),
158 snap_state_range_resolutions: Default::default(),
159 snap_account_range: Default::default(),
160 snap_storage_roots: Default::default(),
161 snap_storage_ranges: Default::default(),
162 snap_storage_range_requests: Default::default(),
163 snap_account_proof: Default::default(),
164 snap_storage_proof: Default::default(),
165 tx: Default::default(),
166 prune_modes: Default::default(),
167 }
168 }
169}
170
171impl<T: NodePrimitives, ChainSpec> MockEthProvider<T, ChainSpec> {
172 pub fn set_snap_state_reads_fail(&self, fail: bool) {
174 self.snap_state_reads_fail.store(fail, Ordering::Relaxed);
175 }
176
177 pub fn set_snap_account_range(&self, accounts: Vec<(B256, Account)>, end: RangeEnd) {
179 self.snap_state_range_available.store(true, Ordering::Relaxed);
180 *self.snap_account_range.lock() = Some((accounts, end));
181 }
182
183 pub fn set_snap_storage_root(&self, hashed_address: B256, storage_root: B256) {
185 self.snap_storage_roots.lock().insert(hashed_address, storage_root);
186 }
187
188 pub fn push_snap_storage_range(&self, slots: Vec<(B256, U256)>, end: RangeEnd) {
190 self.snap_state_range_available.store(true, Ordering::Relaxed);
191 self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::Found(slots, end));
192 }
193
194 pub fn push_missing_snap_storage_account(&self) {
196 self.snap_state_range_available.store(true, Ordering::Relaxed);
197 self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::AccountMissing);
198 }
199
200 pub fn push_unavailable_snap_storage_range(&self) {
202 self.snap_state_range_available.store(true, Ordering::Relaxed);
203 self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::Error);
204 }
205
206 pub fn snap_storage_ranges_remaining(&self) -> usize {
208 self.snap_storage_ranges.lock().len()
209 }
210
211 pub fn snap_storage_range_requests(&self) -> Vec<(B256, B256, B256, usize)> {
213 self.snap_storage_range_requests.lock().clone()
214 }
215
216 pub fn snap_state_range_resolutions(&self) -> usize {
218 self.snap_state_range_resolutions.load(Ordering::Relaxed)
219 }
220
221 pub fn set_snap_account_proof(&self, proof: Option<Vec<Bytes>>) {
223 *self.snap_account_proof.lock() = proof;
224 }
225
226 pub fn set_snap_storage_proof(&self, proof: Option<Vec<Bytes>>) {
228 *self.snap_storage_proof.lock() = proof;
229 }
230
231 fn ensure_snap_state_reads_succeed(&self) -> ProviderResult<()> {
232 if self.snap_state_reads_fail.load(Ordering::Relaxed) {
233 return Err(ProviderError::BestBlockNotFound)
234 }
235 Ok(())
236 }
237
238 pub fn add_block(&self, hash: B256, block: T::Block) {
240 self.add_header(hash, block.header().clone());
241 self.blocks.lock().insert(hash, block);
242 }
243
244 pub fn extend_blocks(&self, iter: impl IntoIterator<Item = (B256, T::Block)>) {
246 for (hash, block) in iter {
247 self.add_block(hash, block)
248 }
249 }
250
251 pub fn add_header(&self, hash: B256, header: <T::Block as Block>::Header) {
253 self.headers.lock().insert(hash, header);
254 }
255
256 pub fn extend_headers(
258 &self,
259 iter: impl IntoIterator<Item = (B256, <T::Block as Block>::Header)>,
260 ) {
261 for (hash, header) in iter {
262 self.add_header(hash, header)
263 }
264 }
265
266 pub fn add_account(&self, address: Address, account: ExtendedAccount) {
268 self.accounts.lock().insert(address, account);
269 }
270
271 pub fn extend_accounts(&self, iter: impl IntoIterator<Item = (Address, ExtendedAccount)>) {
273 for (address, account) in iter {
274 self.add_account(address, account)
275 }
276 }
277
278 pub fn add_receipts(&self, block_number: BlockNumber, receipts: Vec<T::Receipt>) {
280 self.receipts.lock().insert(block_number, receipts);
281 }
282
283 pub fn extend_receipts(&self, iter: impl IntoIterator<Item = (BlockNumber, Vec<T::Receipt>)>) {
285 for (block_number, receipts) in iter {
286 self.add_receipts(block_number, receipts);
287 }
288 }
289
290 pub fn add_block_body_indices(
292 &self,
293 block_number: BlockNumber,
294 indices: StoredBlockBodyIndices,
295 ) {
296 self.block_body_indices.lock().insert(block_number, indices);
297 }
298
299 pub fn add_state_root(&self, state_root: B256) {
301 self.state_roots.lock().push(state_root);
302 }
303
304 pub fn with_chain_spec<C>(self, chain_spec: C) -> MockEthProvider<T, C> {
306 MockEthProvider {
307 blocks: self.blocks,
308 headers: self.headers,
309 receipts: self.receipts,
310 accounts: self.accounts,
311 chain_spec: Arc::new(chain_spec),
312 state_roots: self.state_roots,
313 block_body_indices: self.block_body_indices,
314 bal_store: self.bal_store,
315 snap_state_reads_fail: self.snap_state_reads_fail,
316 snap_state_range_available: self.snap_state_range_available,
317 snap_state_range_resolutions: self.snap_state_range_resolutions,
318 snap_account_range: self.snap_account_range,
319 snap_storage_roots: self.snap_storage_roots,
320 snap_storage_ranges: self.snap_storage_ranges,
321 snap_storage_range_requests: self.snap_storage_range_requests,
322 snap_account_proof: self.snap_account_proof,
323 snap_storage_proof: self.snap_storage_proof,
324 tx: self.tx,
325 prune_modes: self.prune_modes,
326 }
327 }
328
329 pub fn with_genesis_block(self) -> Self
333 where
334 ChainSpec: EthChainSpec<Header = <T::Block as Block>::Header>,
335 <T::Block as Block>::Body: Default,
336 {
337 let genesis_hash = self.chain_spec.genesis_hash();
338 let genesis_header = self.chain_spec.genesis_header().clone();
339 let genesis_block = T::Block::new(genesis_header, Default::default());
340 self.add_block(genesis_hash, genesis_block);
341 self
342 }
343}
344
345impl Default for MockEthProvider {
346 fn default() -> Self {
347 Self::new()
348 }
349}
350
351impl<T: NodePrimitives, ChainSpec> BalProvider for MockEthProvider<T, ChainSpec> {
352 fn bal_store(&self) -> &BalStoreHandle {
353 &self.bal_store
354 }
355}
356
357impl<T, ChainSpec> StateRangeProviderFactory for MockEthProvider<T, ChainSpec>
358where
359 T: NodePrimitives,
360 T::Block: Clone,
361 ChainSpec: Send + Sync + 'static,
362{
363 fn state_range_provider(&self, _state_root: B256) -> ProviderResult<Option<StateRangeView>> {
364 self.snap_state_range_resolutions.fetch_add(1, Ordering::Relaxed);
365 self.ensure_snap_state_reads_succeed()?;
366 if !self.snap_state_range_available.load(Ordering::Relaxed) {
367 return Ok(None)
368 }
369 Ok(Some(Box::new(self.clone())))
370 }
371}
372
373impl<T: NodePrimitives, ChainSpec> StateRangeProvider for MockEthProvider<T, ChainSpec> {
374 fn account_range(
375 &self,
376 _start: B256,
377 _limit: B256,
378 _response_bytes: usize,
379 ) -> RangeResult<(B256, Account)> {
380 self.ensure_snap_state_reads_succeed()?;
381 let (items, end) =
382 self.snap_account_range.lock().clone().ok_or(ProviderError::BestBlockNotFound)?;
383 Ok(RangeResponse { items, end })
384 }
385
386 fn storage_root_by_hash(&self, hashed_address: B256) -> ProviderResult<B256> {
387 self.ensure_snap_state_reads_succeed()?;
388 self.snap_storage_roots
389 .lock()
390 .get(&hashed_address)
391 .copied()
392 .ok_or(ProviderError::BestBlockNotFound)
393 }
394
395 fn storage_range(
396 &self,
397 hashed_address: B256,
398 start: B256,
399 limit: B256,
400 response_bytes: usize,
401 ) -> StorageRangeResult {
402 self.ensure_snap_state_reads_succeed()?;
403 self.snap_storage_range_requests.lock().push((
404 hashed_address,
405 start,
406 limit,
407 response_bytes,
408 ));
409 let outcome =
410 self.snap_storage_ranges.lock().pop_front().ok_or(ProviderError::BestBlockNotFound)?;
411 match outcome {
412 MockStorageRangeOutcome::Error => Err(ProviderError::BestBlockNotFound),
413 MockStorageRangeOutcome::AccountMissing => Ok(None),
414 MockStorageRangeOutcome::Found(items, end) => Ok(Some(RangeResponse { items, end })),
415 }
416 }
417
418 fn account_range_proof(&self, _keys: &[B256]) -> ProviderResult<Vec<Bytes>> {
419 self.ensure_snap_state_reads_succeed()?;
420 self.snap_account_proof.lock().clone().ok_or(ProviderError::BestBlockNotFound)
421 }
422
423 fn storage_range_proof(
424 &self,
425 _hashed_address: B256,
426 _keys: &[B256],
427 ) -> ProviderResult<Vec<Bytes>> {
428 self.ensure_snap_state_reads_succeed()?;
429 self.snap_storage_proof.lock().clone().ok_or(ProviderError::BestBlockNotFound)
430 }
431}
432
433#[derive(Debug, Clone)]
435pub struct ExtendedAccount {
436 account: Account,
437 bytecode: Option<Bytecode>,
438 storage: HashMap<StorageKey, StorageValue>,
439}
440
441impl ExtendedAccount {
442 pub fn new(nonce: u64, balance: U256) -> Self {
444 Self {
445 account: Account { nonce, balance, bytecode_hash: None },
446 bytecode: None,
447 storage: Default::default(),
448 }
449 }
450
451 pub fn with_bytecode(mut self, bytecode: Bytes) -> Self {
453 let hash = keccak256(&bytecode);
454 self.account.bytecode_hash = Some(hash);
455 self.bytecode = Some(Bytecode::new_raw(bytecode));
456 self
457 }
458
459 pub fn extend_storage(
462 mut self,
463 storage: impl IntoIterator<Item = (StorageKey, StorageValue)>,
464 ) -> Self {
465 self.storage.extend(storage);
466 self
467 }
468}
469
470impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
471 for MockEthProvider<T, ChainSpec>
472{
473 type DB = DatabaseMock;
474 type Provider = Self;
475 type ProviderRW = Self;
476
477 fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
478 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
479 }
480
481 fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
482 Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
483 }
484}
485
486impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
487 for MockEthProvider<T, ChainSpec>
488{
489 type Tx = TxMock;
490
491 fn tx_ref(&self) -> &Self::Tx {
492 &self.tx
493 }
494
495 fn tx_mut(&mut self) -> &mut Self::Tx {
496 &mut self.tx
497 }
498
499 fn into_tx(self) -> Self::Tx {
500 self.tx
501 }
502
503 fn commit(self) -> ProviderResult<()> {
504 Ok(self.tx.commit()?)
505 }
506
507 fn prune_modes_ref(&self) -> &PruneModes {
508 &self.prune_modes
509 }
510}
511
512impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
513 for MockEthProvider<T, ChainSpec>
514{
515 type Header = <T::Block as Block>::Header;
516
517 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
518 let lock = self.headers.lock();
519 Ok(lock.get(&block_hash).cloned())
520 }
521
522 fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
523 let lock = self.headers.lock();
524 Ok(lock.values().find(|h| h.number() == num).cloned())
525 }
526
527 fn headers_range(
528 &self,
529 range: impl RangeBounds<BlockNumber>,
530 ) -> ProviderResult<Vec<Self::Header>> {
531 let lock = self.headers.lock();
532
533 let mut headers: Vec<_> =
534 lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
535 headers.sort_by_key(|header| header.number());
536
537 Ok(headers)
538 }
539
540 fn sealed_header(
541 &self,
542 number: BlockNumber,
543 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
544 Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
545 }
546
547 fn sealed_headers_while(
548 &self,
549 range: impl RangeBounds<BlockNumber>,
550 mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
551 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
552 Ok(self
553 .headers_range(range)?
554 .into_iter()
555 .map(SealedHeader::seal_slow)
556 .take_while(|h| predicate(h))
557 .collect())
558 }
559}
560
561impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
562where
563 T: NodePrimitives,
564 ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
565{
566 type ChainSpec = ChainSpec;
567
568 fn chain_spec(&self) -> Arc<Self::ChainSpec> {
569 self.chain_spec.clone()
570 }
571}
572
573impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
574 for MockEthProvider<T, ChainSpec>
575{
576 type Transaction = T::SignedTx;
577
578 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
579 let lock = self.blocks.lock();
580 let tx_number = lock
581 .values()
582 .flat_map(|block| block.body().transactions())
583 .position(|tx| *tx.tx_hash() == tx_hash)
584 .map(|pos| pos as TxNumber);
585
586 Ok(tx_number)
587 }
588
589 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
590 let lock = self.blocks.lock();
591 let transaction =
592 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
593
594 Ok(transaction)
595 }
596
597 fn transaction_by_id_unhashed(
598 &self,
599 id: TxNumber,
600 ) -> ProviderResult<Option<Self::Transaction>> {
601 let lock = self.blocks.lock();
602 let transaction =
603 lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
604
605 Ok(transaction)
606 }
607
608 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
609 Ok(self.blocks.lock().iter().find_map(|(_, block)| {
610 block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
611 }))
612 }
613
614 fn transaction_by_hash_with_meta(
615 &self,
616 hash: TxHash,
617 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
618 let lock = self.blocks.lock();
619 for (block_hash, block) in lock.iter() {
620 for (index, tx) in block.body().transactions_iter().enumerate() {
621 if *tx.tx_hash() == hash {
622 let meta = TransactionMeta {
623 tx_hash: hash,
624 index: index as u64,
625 block_hash: *block_hash,
626 block_number: block.header().number(),
627 base_fee: block.header().base_fee_per_gas(),
628 excess_blob_gas: block.header().excess_blob_gas(),
629 timestamp: block.header().timestamp(),
630 };
631 return Ok(Some((tx.clone(), meta)))
632 }
633 }
634 }
635 Ok(None)
636 }
637
638 fn transactions_by_block(
639 &self,
640 id: BlockHashOrNumber,
641 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
642 Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
643 }
644
645 fn transactions_by_block_range(
646 &self,
647 range: impl RangeBounds<alloy_primitives::BlockNumber>,
648 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
649 let mut map = BTreeMap::new();
651 for block in self.blocks.lock().values() {
652 if range.contains(&block.header().number()) {
653 map.insert(block.header().number(), block.body().clone_transactions());
654 }
655 }
656
657 Ok(map.into_values().collect())
658 }
659
660 fn transactions_by_tx_range(
661 &self,
662 range: impl RangeBounds<TxNumber>,
663 ) -> ProviderResult<Vec<Self::Transaction>> {
664 let lock = self.blocks.lock();
665 let transactions = lock
666 .values()
667 .flat_map(|block| block.body().transactions())
668 .enumerate()
669 .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
670 .map(|(_, tx)| tx.clone())
671 .collect();
672
673 Ok(transactions)
674 }
675
676 fn senders_by_tx_range(
677 &self,
678 range: impl RangeBounds<TxNumber>,
679 ) -> ProviderResult<Vec<Address>> {
680 let lock = self.blocks.lock();
681 let transactions = lock
682 .values()
683 .flat_map(|block| block.body().transactions())
684 .enumerate()
685 .filter_map(|(tx_number, tx)| {
686 if range.contains(&(tx_number as TxNumber)) {
687 tx.recover_signer().ok()
688 } else {
689 None
690 }
691 })
692 .collect();
693
694 Ok(transactions)
695 }
696
697 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
698 self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
699 }
700}
701
702impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
703where
704 T: NodePrimitives,
705 ChainSpec: Send + Sync + 'static,
706{
707 type Receipt = T::Receipt;
708
709 fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
710 Ok(None)
711 }
712
713 fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
714 Ok(None)
715 }
716
717 fn receipts_by_block(
718 &self,
719 block: BlockHashOrNumber,
720 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
721 let receipts_lock = self.receipts.lock();
722
723 match block {
724 BlockHashOrNumber::Hash(hash) => {
725 let headers_lock = self.headers.lock();
727 if let Some(header) = headers_lock.get(&hash) {
728 Ok(receipts_lock.get(&header.number()).cloned())
729 } else {
730 Ok(None)
731 }
732 }
733 BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
734 }
735 }
736
737 fn receipts_by_tx_range(
738 &self,
739 _range: impl RangeBounds<TxNumber>,
740 ) -> ProviderResult<Vec<Self::Receipt>> {
741 Ok(vec![])
742 }
743
744 fn receipts_by_block_range(
745 &self,
746 block_range: RangeInclusive<BlockNumber>,
747 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
748 let receipts_lock = self.receipts.lock();
749 let headers_lock = self.headers.lock();
750
751 let mut result = Vec::new();
752 for block_number in block_range {
753 if headers_lock.values().any(|header| header.number() == block_number) {
755 if let Some(block_receipts) = receipts_lock.get(&block_number) {
756 result.push(block_receipts.clone());
757 } else {
758 result.push(vec![]);
760 }
761 }
762 }
763
764 Ok(result)
765 }
766}
767
768impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
769where
770 T: NodePrimitives,
771 Self: ReceiptProvider + BlockIdReader,
772{
773}
774
775impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
776 for MockEthProvider<T, ChainSpec>
777{
778 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
779 let lock = self.headers.lock();
780 let hash =
781 lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
782 Ok(hash)
783 }
784
785 fn canonical_hashes_range(
786 &self,
787 start: BlockNumber,
788 end: BlockNumber,
789 ) -> ProviderResult<Vec<B256>> {
790 let lock = self.headers.lock();
791 let mut hashes: Vec<_> =
792 lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
793
794 hashes.sort_by_key(|(_, header)| header.number());
795
796 Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
797 }
798}
799
800impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
801 for MockEthProvider<T, ChainSpec>
802{
803 fn chain_info(&self) -> ProviderResult<ChainInfo> {
804 let best_block_number = self.best_block_number()?;
805 let lock = self.headers.lock();
806
807 Ok(lock
808 .iter()
809 .find(|(_, header)| header.number() == best_block_number)
810 .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
811 .unwrap_or_default())
812 }
813
814 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
815 let lock = self.headers.lock();
816 lock.iter()
817 .max_by_key(|h| h.1.number())
818 .map(|(_, header)| header.number())
819 .ok_or(ProviderError::BestBlockNotFound)
820 }
821
822 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
823 self.best_block_number()
824 }
825
826 fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
827 let lock = self.headers.lock();
828 Ok(lock.get(&hash).map(|header| header.number()))
829 }
830}
831
832impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
833 for MockEthProvider<T, ChainSpec>
834{
835 fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
836 Ok(None)
837 }
838
839 fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
840 Ok(None)
841 }
842
843 fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
844 Ok(None)
845 }
846}
847
848impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
850 for MockEthProvider<T, ChainSpec>
851{
852 type Block = T::Block;
853
854 fn find_block_by_hash(
855 &self,
856 hash: B256,
857 _source: BlockSource,
858 ) -> ProviderResult<Option<Self::Block>> {
859 self.block(hash.into())
860 }
861
862 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
863 let lock = self.blocks.lock();
864 match id {
865 BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
866 BlockHashOrNumber::Number(num) => {
867 Ok(lock.values().find(|b| b.header().number() == num).cloned())
868 }
869 }
870 }
871
872 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
873 Ok(None)
874 }
875
876 fn pending_block_and_receipts(
877 &self,
878 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<T::Receipt>)>> {
879 Ok(None)
880 }
881
882 fn recovered_block(
883 &self,
884 _id: BlockHashOrNumber,
885 _transaction_kind: TransactionVariant,
886 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
887 Ok(None)
888 }
889
890 fn sealed_block_with_senders(
891 &self,
892 _id: BlockHashOrNumber,
893 _transaction_kind: TransactionVariant,
894 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
895 Ok(None)
896 }
897
898 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
899 let lock = self.blocks.lock();
900
901 let mut blocks: Vec<_> = lock
902 .values()
903 .filter(|block| range.contains(&block.header().number()))
904 .cloned()
905 .collect();
906 blocks.sort_by_key(|block| block.header().number());
907
908 Ok(blocks)
909 }
910
911 fn block_with_senders_range(
912 &self,
913 _range: RangeInclusive<BlockNumber>,
914 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
915 Ok(vec![])
916 }
917
918 fn recovered_block_range(
919 &self,
920 _range: RangeInclusive<BlockNumber>,
921 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
922 Ok(vec![])
923 }
924
925 fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
926 Ok(None)
927 }
928}
929
930impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
931where
932 ChainSpec: EthChainSpec + Send + Sync + 'static,
933 T: NodePrimitives,
934{
935 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
936 match id {
937 BlockId::Number(num) => self.block_by_number_or_tag(num),
938 BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
939 }
940 }
941
942 fn sealed_header_by_id(
943 &self,
944 id: BlockId,
945 ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
946 self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
947 }
948
949 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
950 match self.block_by_id(id)? {
951 None => Ok(None),
952 Some(block) => Ok(Some(block.into_header())),
953 }
954 }
955}
956
957impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
958 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
959 Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
960 }
961}
962
963impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
964 for MockEthProvider<T, ChainSpec>
965{
966 fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
967 Ok(None)
968 }
969
970 fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
971 Ok(None)
972 }
973
974 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
975 Ok(vec![])
976 }
977}
978
979impl<T: NodePrimitives, ChainSpec: Send + Sync> PruneCheckpointReader
980 for MockEthProvider<T, ChainSpec>
981{
982 fn get_prune_checkpoint(
983 &self,
984 _segment: PruneSegment,
985 ) -> ProviderResult<Option<PruneCheckpoint>> {
986 Ok(None)
987 }
988
989 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
990 Ok(vec![])
991 }
992}
993
994impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
995where
996 T: NodePrimitives,
997 ChainSpec: Send + Sync,
998{
999 fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
1000 Ok(self.state_roots.lock().pop().unwrap_or_default())
1001 }
1002
1003 fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1004 Ok(self.state_roots.lock().pop().unwrap_or_default())
1005 }
1006
1007 fn state_root_with_updates(
1008 &self,
1009 _state: HashedPostState,
1010 ) -> ProviderResult<(B256, TrieUpdates)> {
1011 let state_root = self.state_roots.lock().pop().unwrap_or_default();
1012 Ok((state_root, Default::default()))
1013 }
1014
1015 fn state_root_from_nodes_with_updates(
1016 &self,
1017 _input: TrieInput,
1018 ) -> ProviderResult<(B256, TrieUpdates)> {
1019 let state_root = self.state_roots.lock().pop().unwrap_or_default();
1020 Ok((state_root, Default::default()))
1021 }
1022}
1023
1024impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
1025where
1026 T: NodePrimitives,
1027 ChainSpec: Send + Sync,
1028{
1029 fn storage_root(
1030 &self,
1031 _address: Address,
1032 _hashed_storage: HashedStorage,
1033 ) -> ProviderResult<B256> {
1034 Ok(EMPTY_ROOT_HASH)
1035 }
1036
1037 fn storage_proof(
1038 &self,
1039 _address: Address,
1040 slot: B256,
1041 _hashed_storage: HashedStorage,
1042 ) -> ProviderResult<reth_trie::StorageProof> {
1043 Ok(StorageProof::new(slot))
1044 }
1045
1046 fn storage_multiproof(
1047 &self,
1048 _address: Address,
1049 _slots: &[B256],
1050 _hashed_storage: HashedStorage,
1051 ) -> ProviderResult<StorageMultiProof> {
1052 Ok(StorageMultiProof::empty())
1053 }
1054}
1055
1056impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
1057where
1058 T: NodePrimitives,
1059 ChainSpec: Send + Sync,
1060{
1061 fn proof(
1062 &self,
1063 _input: TrieInput,
1064 address: Address,
1065 _slots: &[B256],
1066 ) -> ProviderResult<AccountProof> {
1067 Ok(AccountProof::new(address))
1068 }
1069
1070 fn multiproof(
1071 &self,
1072 _input: TrieInput,
1073 _targets: MultiProofTargets,
1074 ) -> ProviderResult<MultiProof> {
1075 Ok(MultiProof::default())
1076 }
1077
1078 fn witness(
1079 &self,
1080 _input: TrieInput,
1081 _target: HashedPostState,
1082 _mode: reth_trie::ExecutionWitnessMode,
1083 ) -> ProviderResult<Vec<Bytes>> {
1084 Ok(Vec::default())
1085 }
1086}
1087
1088impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
1089 for MockEthProvider<T, ChainSpec>
1090{
1091 fn hashed_post_state(&self, _state: &revm::database::BundleState) -> HashedPostState {
1092 HashedPostState::default()
1093 }
1094}
1095
1096impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
1097where
1098 T: NodePrimitives,
1099 ChainSpec: EthChainSpec + Send + Sync + 'static,
1100{
1101 fn storage(
1102 &self,
1103 account: Address,
1104 storage_key: StorageKey,
1105 ) -> ProviderResult<Option<StorageValue>> {
1106 let lock = self.accounts.lock();
1107 Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
1108 }
1109}
1110
1111impl<T, ChainSpec> BytecodeReader for MockEthProvider<T, ChainSpec>
1112where
1113 T: NodePrimitives,
1114 ChainSpec: Send + Sync,
1115{
1116 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
1117 let lock = self.accounts.lock();
1118 Ok(lock.values().find_map(|account| {
1119 match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
1120 (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
1121 Some(bytecode.clone())
1122 }
1123 _ => None,
1124 }
1125 }))
1126 }
1127}
1128
1129impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageSettingsCache
1130 for MockEthProvider<T, ChainSpec>
1131{
1132 fn cached_storage_settings(&self) -> StorageSettings {
1133 StorageSettings::default()
1134 }
1135
1136 fn set_storage_settings_cache(&self, _settings: StorageSettings) {}
1137}
1138
1139impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
1140 for MockEthProvider<T, ChainSpec>
1141{
1142 fn latest(&self) -> ProviderResult<StateProviderBox> {
1143 self.ensure_snap_state_reads_succeed()?;
1144 Ok(Box::new(self.clone()))
1145 }
1146
1147 fn state_by_block_number_or_tag(
1148 &self,
1149 number_or_tag: BlockNumberOrTag,
1150 ) -> ProviderResult<StateProviderBox> {
1151 match number_or_tag {
1152 BlockNumberOrTag::Latest => self.latest(),
1153 BlockNumberOrTag::Finalized => {
1154 let hash =
1156 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
1157
1158 self.history_by_block_hash(hash)
1160 }
1161 BlockNumberOrTag::Safe => {
1162 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
1164
1165 self.history_by_block_hash(hash)
1166 }
1167 BlockNumberOrTag::Earliest => {
1168 self.history_by_block_number(self.earliest_block_number()?)
1169 }
1170 BlockNumberOrTag::Pending => self.pending(),
1171 BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1172 }
1173 }
1174
1175 fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
1176 Ok(Box::new(self.clone()))
1177 }
1178
1179 fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1180 Ok(Box::new(self.clone()))
1181 }
1182
1183 fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1184 Ok(Box::new(self.clone()))
1185 }
1186
1187 fn pending(&self) -> ProviderResult<StateProviderBox> {
1188 Ok(Box::new(self.clone()))
1189 }
1190
1191 fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
1192 Ok(Some(Box::new(self.clone())))
1193 }
1194
1195 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1196 Ok(Some(Box::new(self.clone())))
1197 }
1198}
1199
1200impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
1201 for MockEthProvider<T, ChainSpec>
1202{
1203 fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
1204 Ok(self.block_body_indices.lock().get(&num).copied())
1205 }
1206 fn block_body_indices_range(
1207 &self,
1208 _range: RangeInclusive<BlockNumber>,
1209 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
1210 Ok(vec![])
1211 }
1212}
1213
1214impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
1215 fn account_block_changeset(
1216 &self,
1217 _block_number: BlockNumber,
1218 ) -> ProviderResult<Vec<AccountBeforeTx>> {
1219 Ok(Vec::default())
1220 }
1221
1222 fn get_account_before_block(
1223 &self,
1224 _block_number: BlockNumber,
1225 _address: Address,
1226 ) -> ProviderResult<Option<AccountBeforeTx>> {
1227 Ok(None)
1228 }
1229
1230 fn account_changesets_range(
1231 &self,
1232 _range: impl core::ops::RangeBounds<BlockNumber>,
1233 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
1234 Ok(Vec::default())
1235 }
1236}
1237
1238impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageChangeSetReader
1239 for MockEthProvider<T, ChainSpec>
1240{
1241 fn storage_changeset(
1242 &self,
1243 _block_number: BlockNumber,
1244 ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1245 Ok(Vec::default())
1246 }
1247
1248 fn get_storage_before_block(
1249 &self,
1250 _block_number: BlockNumber,
1251 _address: Address,
1252 _storage_key: B256,
1253 ) -> ProviderResult<Option<StorageEntry>> {
1254 Ok(None)
1255 }
1256
1257 fn storage_changesets_range(
1258 &self,
1259 _range: impl RangeBounds<BlockNumber>,
1260 ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1261 Ok(Vec::default())
1262 }
1263}
1264
1265impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
1266 type Receipt = T::Receipt;
1267
1268 fn get_state(
1269 &self,
1270 _block: BlockNumber,
1271 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1272 Ok(None)
1273 }
1274}
1275
1276impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1277 for MockEthProvider<T, ChainSpec>
1278{
1279 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1280 broadcast::channel(1).1
1281 }
1282}
1283
1284impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1285 for MockEthProvider<T, ChainSpec>
1286{
1287 type Primitives = T;
1288}
1289
1290#[cfg(test)]
1291mod tests {
1292 use super::*;
1293 use alloy_consensus::Header;
1294 use alloy_primitives::BlockHash;
1295 use reth_ethereum_primitives::Receipt;
1296
1297 #[test]
1298 fn test_mock_provider_receipts() {
1299 let provider = MockEthProvider::<EthPrimitives>::new();
1300
1301 let block_hash = BlockHash::random();
1302 let block_number = 1u64;
1303 let header = Header { number: block_number, ..Default::default() };
1304
1305 let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1306 let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1307 let receipts = vec![receipt1, receipt2];
1308
1309 provider.add_header(block_hash, header);
1310 provider.add_receipts(block_number, receipts.clone());
1311
1312 let result = provider.receipts_by_block(block_hash.into()).unwrap();
1313 assert_eq!(result, Some(receipts.clone()));
1314
1315 let result = provider.receipts_by_block(block_number.into()).unwrap();
1316 assert_eq!(result, Some(receipts.clone()));
1317
1318 let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1319 assert_eq!(range_result, vec![receipts]);
1320
1321 let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1322 assert_eq!(non_existent, None);
1323
1324 let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1325 assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1326 }
1327
1328 #[test]
1329 fn test_mock_provider_receipts_multiple_blocks() {
1330 let provider = MockEthProvider::<EthPrimitives>::new();
1331
1332 let block1_hash = BlockHash::random();
1333 let block2_hash = BlockHash::random();
1334 let block1_number = 1u64;
1335 let block2_number = 2u64;
1336
1337 let header1 = Header { number: block1_number, ..Default::default() };
1338 let header2 = Header { number: block2_number, ..Default::default() };
1339
1340 let receipts1 =
1341 vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1342 let receipts2 =
1343 vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1344
1345 provider.add_header(block1_hash, header1);
1346 provider.add_header(block2_hash, header2);
1347 provider.add_receipts(block1_number, receipts1.clone());
1348 provider.add_receipts(block2_number, receipts2.clone());
1349
1350 let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1351 assert_eq!(range_result.len(), 2);
1352 assert_eq!(range_result[0], receipts1);
1353 assert_eq!(range_result[1], receipts2);
1354
1355 let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1356 assert_eq!(partial_range.len(), 1);
1357 assert_eq!(partial_range[0], receipts1);
1358 }
1359}