1use crate::{
2 providers::{
3 ConsistentProvider, ProviderNodeTypes, RocksDBProvider, StaticFileProvider,
4 StaticFileProviderRWRefMut,
5 },
6 AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
7 BlockSource, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions,
8 ChainSpecProvider, ChainStateBlockReader, ChangeSetReader, DatabaseProviderFactory,
9 HashedPostStateProvider, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader,
10 ReceiptProvider, ReceiptProviderIdExt, RocksDBProviderFactory, StageCheckpointReader,
11 StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory,
12 TransactionVariant, TransactionsProvider,
13};
14use alloy_consensus::transaction::TransactionMeta;
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
16use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256};
17use alloy_rpc_types_engine::ForkchoiceState;
18use reth_chain_state::{
19 BlockState, CanonicalInMemoryState, ForkChoiceNotifications, ForkChoiceSubscriptions,
20 MemoryOverlayStateProvider, PersistedBlockNotifications, PersistedBlockSubscriptions,
21};
22use reth_chainspec::ChainInfo;
23use reth_db_api::models::{AccountBeforeTx, BlockNumberAddress, StoredBlockBodyIndices};
24use reth_execution_types::ExecutionOutcome;
25use reth_node_types::{BlockTy, HeaderTy, NodeTypesWithDB, ReceiptTy, TxTy};
26use reth_primitives_traits::{Account, RecoveredBlock, SealedHeader, StorageEntry};
27use reth_prune_types::{PruneCheckpoint, PruneSegment};
28use reth_stages_types::{StageCheckpoint, StageId};
29use reth_static_file_types::StaticFileSegment;
30use reth_storage_api::{BlockBodyIndicesProvider, NodePrimitivesProvider, StorageChangeSetReader};
31use reth_storage_errors::provider::ProviderResult;
32use reth_trie::{HashedPostState, KeccakKeyHasher};
33use revm_database::BundleState;
34use std::{
35 ops::{RangeBounds, RangeInclusive},
36 sync::Arc,
37 time::Instant,
38};
39use tracing::trace;
40
41#[derive(Debug)]
47pub struct BlockchainProvider<N: NodeTypesWithDB> {
48 pub(crate) database: ProviderFactory<N>,
50 pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
53}
54
55impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
56 fn clone(&self) -> Self {
57 Self {
58 database: self.database.clone(),
59 canonical_in_memory_state: self.canonical_in_memory_state.clone(),
60 }
61 }
62}
63
64impl<N: ProviderNodeTypes> BlockchainProvider<N> {
65 pub fn new(storage: ProviderFactory<N>) -> ProviderResult<Self> {
68 let provider = storage.provider()?;
69 let best = provider.chain_info()?;
70 match provider.header_by_number(best.best_number)? {
71 Some(header) => {
72 drop(provider);
73 Ok(Self::with_latest(storage, SealedHeader::new(header, best.best_hash))?)
74 }
75 None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
76 }
77 }
78
79 pub fn with_latest(
85 storage: ProviderFactory<N>,
86 latest: SealedHeader<HeaderTy<N>>,
87 ) -> ProviderResult<Self> {
88 let provider = storage.provider()?;
89 let finalized_header = provider
90 .last_finalized_block_number()?
91 .map(|num| provider.sealed_header(num))
92 .transpose()?
93 .flatten();
94 let safe_header = provider
95 .last_safe_block_number()?
96 .or_else(|| {
97 provider.last_finalized_block_number().ok().flatten()
100 })
101 .map(|num| provider.sealed_header(num))
102 .transpose()?
103 .flatten();
104 Ok(Self {
105 database: storage,
106 canonical_in_memory_state: CanonicalInMemoryState::with_head(
107 latest,
108 finalized_header,
109 safe_header,
110 ),
111 })
112 }
113
114 pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
116 self.canonical_in_memory_state.clone()
117 }
118
119 #[track_caller]
123 pub fn consistent_provider(&self) -> ProviderResult<ConsistentProvider<N>> {
124 ConsistentProvider::new(self.database.clone(), self.canonical_in_memory_state())
125 }
126
127 fn block_state_provider(
129 &self,
130 state: &BlockState<N::Primitives>,
131 ) -> ProviderResult<MemoryOverlayStateProvider<N::Primitives>> {
132 let anchor_hash = state.anchor().hash;
133 let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
134 Ok(state.state_provider(latest_historical))
135 }
136
137 pub fn get_state(
141 &self,
142 range: RangeInclusive<BlockNumber>,
143 ) -> ProviderResult<Option<ExecutionOutcome<ReceiptTy<N>>>> {
144 self.consistent_provider()?.get_state(range)
145 }
146}
147
148impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
149 type Primitives = N::Primitives;
150}
151
152impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
153 type DB = N::DB;
154 type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
155 type ProviderRW = <ProviderFactory<N> as DatabaseProviderFactory>::ProviderRW;
156
157 fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
158 self.database.database_provider_ro()
159 }
160
161 fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
162 self.database.database_provider_rw()
163 }
164}
165
166impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
167 fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
168 self.database.static_file_provider()
169 }
170
171 fn get_static_file_writer(
172 &self,
173 block: BlockNumber,
174 segment: StaticFileSegment,
175 ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
176 self.database.get_static_file_writer(block, segment)
177 }
178}
179
180impl<N: ProviderNodeTypes> RocksDBProviderFactory for BlockchainProvider<N> {
181 fn rocksdb_provider(&self) -> RocksDBProvider {
182 self.database.rocksdb_provider()
183 }
184
185 fn set_pending_rocksdb_batch(&self, _batch: rocksdb::WriteBatchWithTransaction<true>) {
186 unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::set_pending_rocksdb_batch instead")
187 }
188
189 fn commit_pending_rocksdb_batches(&self) -> ProviderResult<()> {
190 unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::commit_pending_rocksdb_batches instead")
191 }
192}
193
194impl<N: ProviderNodeTypes> HeaderProvider for BlockchainProvider<N> {
195 type Header = HeaderTy<N>;
196
197 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
198 self.consistent_provider()?.header(block_hash)
199 }
200
201 fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
202 self.consistent_provider()?.header_by_number(num)
203 }
204
205 fn headers_range(
206 &self,
207 range: impl RangeBounds<BlockNumber>,
208 ) -> ProviderResult<Vec<Self::Header>> {
209 self.consistent_provider()?.headers_range(range)
210 }
211
212 fn sealed_header(
213 &self,
214 number: BlockNumber,
215 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
216 self.consistent_provider()?.sealed_header(number)
217 }
218
219 fn sealed_headers_range(
220 &self,
221 range: impl RangeBounds<BlockNumber>,
222 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
223 self.consistent_provider()?.sealed_headers_range(range)
224 }
225
226 fn sealed_headers_while(
227 &self,
228 range: impl RangeBounds<BlockNumber>,
229 predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
230 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
231 self.consistent_provider()?.sealed_headers_while(range, predicate)
232 }
233}
234
235impl<N: ProviderNodeTypes> BlockHashReader for BlockchainProvider<N> {
236 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
237 self.consistent_provider()?.block_hash(number)
238 }
239
240 fn canonical_hashes_range(
241 &self,
242 start: BlockNumber,
243 end: BlockNumber,
244 ) -> ProviderResult<Vec<B256>> {
245 self.consistent_provider()?.canonical_hashes_range(start, end)
246 }
247}
248
249impl<N: ProviderNodeTypes> BlockNumReader for BlockchainProvider<N> {
250 fn chain_info(&self) -> ProviderResult<ChainInfo> {
251 Ok(self.canonical_in_memory_state.chain_info())
252 }
253
254 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
255 Ok(self.canonical_in_memory_state.get_canonical_block_number())
256 }
257
258 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
259 self.database.last_block_number()
260 }
261
262 fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
263 self.database.earliest_block_number()
264 }
265
266 fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
267 self.consistent_provider()?.block_number(hash)
268 }
269}
270
271impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
272 fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
273 Ok(self.canonical_in_memory_state.pending_block_num_hash())
274 }
275
276 fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
277 Ok(self.canonical_in_memory_state.get_safe_num_hash())
278 }
279
280 fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
281 Ok(self.canonical_in_memory_state.get_finalized_num_hash())
282 }
283}
284
285impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
286 type Block = BlockTy<N>;
287
288 fn find_block_by_hash(
289 &self,
290 hash: B256,
291 source: BlockSource,
292 ) -> ProviderResult<Option<Self::Block>> {
293 self.consistent_provider()?.find_block_by_hash(hash, source)
294 }
295
296 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
297 self.consistent_provider()?.block(id)
298 }
299
300 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
301 Ok(self.canonical_in_memory_state.pending_recovered_block())
302 }
303
304 fn pending_block_and_receipts(
305 &self,
306 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
307 Ok(self.canonical_in_memory_state.pending_block_and_receipts())
308 }
309
310 fn recovered_block(
317 &self,
318 id: BlockHashOrNumber,
319 transaction_kind: TransactionVariant,
320 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
321 self.consistent_provider()?.recovered_block(id, transaction_kind)
322 }
323
324 fn sealed_block_with_senders(
325 &self,
326 id: BlockHashOrNumber,
327 transaction_kind: TransactionVariant,
328 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
329 self.consistent_provider()?.sealed_block_with_senders(id, transaction_kind)
330 }
331
332 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
333 self.consistent_provider()?.block_range(range)
334 }
335
336 fn block_with_senders_range(
337 &self,
338 range: RangeInclusive<BlockNumber>,
339 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
340 self.consistent_provider()?.block_with_senders_range(range)
341 }
342
343 fn recovered_block_range(
344 &self,
345 range: RangeInclusive<BlockNumber>,
346 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
347 self.consistent_provider()?.recovered_block_range(range)
348 }
349
350 fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
351 self.consistent_provider()?.block_by_transaction_id(id)
352 }
353}
354
355impl<N: ProviderNodeTypes> TransactionsProvider for BlockchainProvider<N> {
356 type Transaction = TxTy<N>;
357
358 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
359 self.consistent_provider()?.transaction_id(tx_hash)
360 }
361
362 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
363 self.consistent_provider()?.transaction_by_id(id)
364 }
365
366 fn transaction_by_id_unhashed(
367 &self,
368 id: TxNumber,
369 ) -> ProviderResult<Option<Self::Transaction>> {
370 self.consistent_provider()?.transaction_by_id_unhashed(id)
371 }
372
373 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
374 self.consistent_provider()?.transaction_by_hash(hash)
375 }
376
377 fn transaction_by_hash_with_meta(
378 &self,
379 tx_hash: TxHash,
380 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
381 self.consistent_provider()?.transaction_by_hash_with_meta(tx_hash)
382 }
383
384 fn transactions_by_block(
385 &self,
386 id: BlockHashOrNumber,
387 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
388 self.consistent_provider()?.transactions_by_block(id)
389 }
390
391 fn transactions_by_block_range(
392 &self,
393 range: impl RangeBounds<BlockNumber>,
394 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
395 self.consistent_provider()?.transactions_by_block_range(range)
396 }
397
398 fn transactions_by_tx_range(
399 &self,
400 range: impl RangeBounds<TxNumber>,
401 ) -> ProviderResult<Vec<Self::Transaction>> {
402 self.consistent_provider()?.transactions_by_tx_range(range)
403 }
404
405 fn senders_by_tx_range(
406 &self,
407 range: impl RangeBounds<TxNumber>,
408 ) -> ProviderResult<Vec<Address>> {
409 self.consistent_provider()?.senders_by_tx_range(range)
410 }
411
412 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
413 self.consistent_provider()?.transaction_sender(id)
414 }
415}
416
417impl<N: ProviderNodeTypes> ReceiptProvider for BlockchainProvider<N> {
418 type Receipt = ReceiptTy<N>;
419
420 fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
421 self.consistent_provider()?.receipt(id)
422 }
423
424 fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
425 self.consistent_provider()?.receipt_by_hash(hash)
426 }
427
428 fn receipts_by_block(
429 &self,
430 block: BlockHashOrNumber,
431 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
432 self.consistent_provider()?.receipts_by_block(block)
433 }
434
435 fn receipts_by_tx_range(
436 &self,
437 range: impl RangeBounds<TxNumber>,
438 ) -> ProviderResult<Vec<Self::Receipt>> {
439 self.consistent_provider()?.receipts_by_tx_range(range)
440 }
441
442 fn receipts_by_block_range(
443 &self,
444 block_range: RangeInclusive<BlockNumber>,
445 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
446 self.consistent_provider()?.receipts_by_block_range(block_range)
447 }
448}
449
450impl<N: ProviderNodeTypes> ReceiptProviderIdExt for BlockchainProvider<N> {
451 fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
452 self.consistent_provider()?.receipts_by_block_id(block)
453 }
454}
455
456impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for BlockchainProvider<N> {
457 fn block_body_indices(
458 &self,
459 number: BlockNumber,
460 ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
461 self.consistent_provider()?.block_body_indices(number)
462 }
463
464 fn block_body_indices_range(
465 &self,
466 range: RangeInclusive<BlockNumber>,
467 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
468 self.consistent_provider()?.block_body_indices_range(range)
469 }
470}
471
472impl<N: ProviderNodeTypes> StageCheckpointReader for BlockchainProvider<N> {
473 fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
474 self.consistent_provider()?.get_stage_checkpoint(id)
475 }
476
477 fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
478 self.consistent_provider()?.get_stage_checkpoint_progress(id)
479 }
480
481 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
482 self.consistent_provider()?.get_all_checkpoints()
483 }
484}
485
486impl<N: ProviderNodeTypes> PruneCheckpointReader for BlockchainProvider<N> {
487 fn get_prune_checkpoint(
488 &self,
489 segment: PruneSegment,
490 ) -> ProviderResult<Option<PruneCheckpoint>> {
491 self.consistent_provider()?.get_prune_checkpoint(segment)
492 }
493
494 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
495 self.consistent_provider()?.get_prune_checkpoints()
496 }
497}
498
499impl<N: NodeTypesWithDB> ChainSpecProvider for BlockchainProvider<N> {
500 type ChainSpec = N::ChainSpec;
501
502 fn chain_spec(&self) -> Arc<N::ChainSpec> {
503 self.database.chain_spec()
504 }
505}
506
507impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider<N> {
508 fn latest(&self) -> ProviderResult<StateProviderBox> {
510 trace!(target: "providers::blockchain", "Getting latest block state provider");
511 if let Some(state) = self.canonical_in_memory_state.head_state() {
513 trace!(target: "providers::blockchain", "Using head state for latest state provider");
514 Ok(self.block_state_provider(&state)?.boxed())
515 } else {
516 trace!(target: "providers::blockchain", "Using database state for latest state provider");
517 self.database.latest()
518 }
519 }
520
521 fn state_by_block_number_or_tag(
523 &self,
524 number_or_tag: BlockNumberOrTag,
525 ) -> ProviderResult<StateProviderBox> {
526 match number_or_tag {
527 BlockNumberOrTag::Latest => self.latest(),
528 BlockNumberOrTag::Finalized => {
529 let hash =
531 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
532 self.state_by_block_hash(hash)
533 }
534 BlockNumberOrTag::Safe => {
535 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
537 self.state_by_block_hash(hash)
538 }
539 BlockNumberOrTag::Earliest => {
540 self.history_by_block_number(self.earliest_block_number()?)
541 }
542 BlockNumberOrTag::Pending => self.pending(),
543 BlockNumberOrTag::Number(num) => {
544 let hash = self
545 .block_hash(num)?
546 .ok_or_else(|| ProviderError::HeaderNotFound(num.into()))?;
547 self.state_by_block_hash(hash)
548 }
549 }
550 }
551
552 fn history_by_block_number(
553 &self,
554 block_number: BlockNumber,
555 ) -> ProviderResult<StateProviderBox> {
556 trace!(target: "providers::blockchain", ?block_number, "Getting history by block number");
557 let provider = self.consistent_provider()?;
558 let hash = provider
559 .block_hash(block_number)?
560 .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
561 provider.into_state_provider_at_block_hash(hash)
562 }
563
564 fn history_by_block_hash(&self, block_hash: BlockHash) -> ProviderResult<StateProviderBox> {
565 trace!(target: "providers::blockchain", ?block_hash, "Getting history by block hash");
566 self.consistent_provider()?.into_state_provider_at_block_hash(block_hash)
567 }
568
569 fn state_by_block_hash(&self, hash: BlockHash) -> ProviderResult<StateProviderBox> {
570 trace!(target: "providers::blockchain", ?hash, "Getting state by block hash");
571 if let Ok(state) = self.history_by_block_hash(hash) {
572 Ok(state)
574 } else if let Ok(Some(pending)) = self.pending_state_by_hash(hash) {
575 Ok(pending)
577 } else {
578 Err(ProviderError::StateForHashNotFound(hash))
580 }
581 }
582
583 fn pending(&self) -> ProviderResult<StateProviderBox> {
588 trace!(target: "providers::blockchain", "Getting provider for pending state");
589
590 if let Some(pending) = self.canonical_in_memory_state.pending_state() {
591 return Ok(Box::new(self.block_state_provider(&pending)?));
593 }
594
595 self.latest()
597 }
598
599 fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
600 if let Some(pending) = self.canonical_in_memory_state.pending_state() &&
601 pending.hash() == block_hash
602 {
603 return Ok(Some(Box::new(self.block_state_provider(&pending)?)));
604 }
605 Ok(None)
606 }
607
608 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
609 if let Some(pending) = self.canonical_in_memory_state.pending_state() {
610 return Ok(Some(Box::new(self.block_state_provider(&pending)?)))
611 }
612
613 Ok(None)
614 }
615}
616
617impl<N: NodeTypesWithDB> HashedPostStateProvider for BlockchainProvider<N> {
618 fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState {
619 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
620 }
621}
622
623impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider<N> {
624 type Header = HeaderTy<N>;
625
626 fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
627 self.canonical_in_memory_state.on_forkchoice_update_received();
629 }
630
631 fn last_received_update_timestamp(&self) -> Option<Instant> {
632 self.canonical_in_memory_state.last_received_update_timestamp()
633 }
634
635 fn set_canonical_head(&self, header: SealedHeader<Self::Header>) {
636 self.canonical_in_memory_state.set_canonical_head(header);
637 }
638
639 fn set_safe(&self, header: SealedHeader<Self::Header>) {
640 self.canonical_in_memory_state.set_safe(header);
641 }
642
643 fn set_finalized(&self, header: SealedHeader<Self::Header>) {
644 self.canonical_in_memory_state.set_finalized(header);
645 }
646}
647
648impl<N: ProviderNodeTypes> BlockReaderIdExt for BlockchainProvider<N>
649where
650 Self: ReceiptProviderIdExt,
651{
652 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
653 self.consistent_provider()?.block_by_id(id)
654 }
655
656 fn header_by_number_or_tag(
657 &self,
658 id: BlockNumberOrTag,
659 ) -> ProviderResult<Option<Self::Header>> {
660 self.consistent_provider()?.header_by_number_or_tag(id)
661 }
662
663 fn sealed_header_by_number_or_tag(
664 &self,
665 id: BlockNumberOrTag,
666 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
667 self.consistent_provider()?.sealed_header_by_number_or_tag(id)
668 }
669
670 fn sealed_header_by_id(
671 &self,
672 id: BlockId,
673 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
674 self.consistent_provider()?.sealed_header_by_id(id)
675 }
676
677 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
678 self.consistent_provider()?.header_by_id(id)
679 }
680}
681
682impl<N: ProviderNodeTypes> CanonStateSubscriptions for BlockchainProvider<N> {
683 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<Self::Primitives> {
684 self.canonical_in_memory_state.subscribe_canon_state()
685 }
686}
687
688impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider<N> {
689 type Header = HeaderTy<N>;
690
691 fn subscribe_safe_block(&self) -> ForkChoiceNotifications<Self::Header> {
692 let receiver = self.canonical_in_memory_state.subscribe_safe_block();
693 ForkChoiceNotifications(receiver)
694 }
695
696 fn subscribe_finalized_block(&self) -> ForkChoiceNotifications<Self::Header> {
697 let receiver = self.canonical_in_memory_state.subscribe_finalized_block();
698 ForkChoiceNotifications(receiver)
699 }
700}
701
702impl<N: ProviderNodeTypes> PersistedBlockSubscriptions for BlockchainProvider<N> {
703 fn subscribe_persisted_block(&self) -> PersistedBlockNotifications {
704 let receiver = self.canonical_in_memory_state.subscribe_persisted_block();
705 PersistedBlockNotifications(receiver)
706 }
707}
708
709impl<N: ProviderNodeTypes> StorageChangeSetReader for BlockchainProvider<N> {
710 fn storage_changeset(
711 &self,
712 block_number: BlockNumber,
713 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
714 self.consistent_provider()?.storage_changeset(block_number)
715 }
716
717 fn get_storage_before_block(
718 &self,
719 block_number: BlockNumber,
720 address: Address,
721 storage_key: B256,
722 ) -> ProviderResult<Option<StorageEntry>> {
723 self.consistent_provider()?.get_storage_before_block(block_number, address, storage_key)
724 }
725
726 fn storage_changesets_range(
727 &self,
728 range: impl RangeBounds<BlockNumber>,
729 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
730 self.consistent_provider()?.storage_changesets_range(range)
731 }
732}
733
734impl<N: ProviderNodeTypes> ChangeSetReader for BlockchainProvider<N> {
735 fn account_block_changeset(
736 &self,
737 block_number: BlockNumber,
738 ) -> ProviderResult<Vec<AccountBeforeTx>> {
739 self.consistent_provider()?.account_block_changeset(block_number)
740 }
741
742 fn get_account_before_block(
743 &self,
744 block_number: BlockNumber,
745 address: Address,
746 ) -> ProviderResult<Option<AccountBeforeTx>> {
747 self.consistent_provider()?.get_account_before_block(block_number, address)
748 }
749
750 fn account_changesets_range(
751 &self,
752 range: impl core::ops::RangeBounds<BlockNumber>,
753 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
754 self.consistent_provider()?.account_changesets_range(range)
755 }
756}
757
758impl<N: ProviderNodeTypes> AccountReader for BlockchainProvider<N> {
759 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
761 self.consistent_provider()?.basic_account(address)
762 }
763}
764
765impl<N: ProviderNodeTypes> StateReader for BlockchainProvider<N> {
766 type Receipt = ReceiptTy<N>;
767
768 fn get_state(
778 &self,
779 block: BlockNumber,
780 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
781 StateReader::get_state(&self.consistent_provider()?, block)
782 }
783}
784
785#[cfg(test)]
786mod tests {
787 use crate::{
788 providers::BlockchainProvider,
789 test_utils::{
790 create_test_provider_factory, create_test_provider_factory_with_chain_spec,
791 MockNodeTypesWithDB,
792 },
793 BlockWriter, CanonChainTracker, ProviderFactory, SaveBlocksMode,
794 };
795 use alloy_eips::{BlockHashOrNumber, BlockNumHash, BlockNumberOrTag};
796 use alloy_primitives::{BlockNumber, TxNumber, B256};
797 use itertools::Itertools;
798 use rand::Rng;
799 use reth_chain_state::{
800 test_utils::TestBlockBuilder, CanonStateNotification, CanonStateSubscriptions,
801 CanonicalInMemoryState, ExecutedBlock, NewCanonicalChain,
802 };
803 use reth_chainspec::{ChainSpec, MAINNET};
804 use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
805 use reth_errors::ProviderError;
806 use reth_ethereum_primitives::{Block, Receipt};
807 use reth_execution_types::{
808 BlockExecutionOutput, BlockExecutionResult, Chain, ExecutionOutcome,
809 };
810 use reth_primitives_traits::{RecoveredBlock, SealedBlock, SignerRecoverable};
811 use reth_storage_api::{
812 BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader,
813 BlockReaderIdExt, BlockSource, ChangeSetReader, DBProvider, DatabaseProviderFactory,
814 HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, StateProviderFactory,
815 StateWriteConfig, StateWriter, TransactionVariant, TransactionsProvider,
816 };
817 use reth_testing_utils::generators::{
818 self, random_block, random_block_range, random_changeset_range, random_eoa_accounts,
819 random_receipt, BlockParams, BlockRangeParams,
820 };
821 use revm_database::{BundleState, OriginalValuesKnown};
822 use std::{
823 collections::BTreeMap,
824 ops::{Bound, Range, RangeBounds},
825 sync::Arc,
826 };
827
828 const TEST_BLOCKS_COUNT: usize = 5;
829
830 const TEST_TRANSACTIONS_COUNT: u8 = 4;
831
832 fn random_blocks(
833 rng: &mut impl Rng,
834 database_blocks: usize,
835 in_memory_blocks: usize,
836 requests_count: Option<Range<u8>>,
837 withdrawals_count: Option<Range<u8>>,
838 tx_count: impl RangeBounds<u8>,
839 ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
840 let block_range = (database_blocks + in_memory_blocks - 1) as u64;
841
842 let tx_start = match tx_count.start_bound() {
843 Bound::Included(&n) | Bound::Excluded(&n) => n,
844 Bound::Unbounded => u8::MIN,
845 };
846 let tx_end = match tx_count.end_bound() {
847 Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
848 Bound::Unbounded => u8::MAX,
849 };
850
851 let blocks = random_block_range(
852 rng,
853 0..=block_range,
854 BlockRangeParams {
855 parent: Some(B256::ZERO),
856 tx_count: tx_start..tx_end,
857 requests_count,
858 withdrawals_count,
859 },
860 );
861 let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
862 (database_blocks.to_vec(), in_memory_blocks.to_vec())
863 }
864
865 #[expect(clippy::type_complexity)]
866 fn provider_with_chain_spec_and_random_blocks(
867 rng: &mut impl Rng,
868 chain_spec: Arc<ChainSpec>,
869 database_blocks: usize,
870 in_memory_blocks: usize,
871 block_range_params: BlockRangeParams,
872 ) -> eyre::Result<(
873 BlockchainProvider<MockNodeTypesWithDB>,
874 Vec<SealedBlock<Block>>,
875 Vec<SealedBlock<Block>>,
876 Vec<Vec<Receipt>>,
877 )> {
878 let (database_blocks, in_memory_blocks) = random_blocks(
879 rng,
880 database_blocks,
881 in_memory_blocks,
882 block_range_params.requests_count,
883 block_range_params.withdrawals_count,
884 block_range_params.tx_count,
885 );
886
887 let receipts: Vec<Vec<_>> = database_blocks
888 .iter()
889 .chain(in_memory_blocks.iter())
890 .map(|block| block.body().transactions.iter())
891 .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
892 .collect();
893
894 let factory = create_test_provider_factory_with_chain_spec(chain_spec);
895 let provider_rw = factory.database_provider_rw()?;
896
897 for block in &database_blocks {
899 provider_rw.insert_block(
900 &block.clone().try_recover().expect("failed to seal block with senders"),
901 )?;
902 }
903
904 if let Some(first_block) = database_blocks.first() {
906 provider_rw.write_state(
907 &ExecutionOutcome {
908 first_block: first_block.number,
909 receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
910 ..Default::default()
911 },
912 OriginalValuesKnown::No,
913 StateWriteConfig::default(),
914 )?;
915 }
916
917 provider_rw.commit()?;
918
919 let provider = BlockchainProvider::new(factory)?;
920
921 let chain = NewCanonicalChain::Commit {
923 new: in_memory_blocks
924 .iter()
925 .map(|block| {
926 let senders = block.senders().expect("failed to recover senders");
927 let block_receipts = receipts.get(block.number as usize).unwrap().clone();
928 let execution_outcome = BlockExecutionOutput {
929 result: BlockExecutionResult {
930 receipts: block_receipts,
931 requests: Default::default(),
932 gas_used: 0,
933 blob_gas_used: 0,
934 },
935 state: BundleState::default(),
936 };
937
938 ExecutedBlock {
939 recovered_block: Arc::new(RecoveredBlock::new_sealed(
940 block.clone(),
941 senders,
942 )),
943 execution_output: execution_outcome.into(),
944 ..Default::default()
945 }
946 })
947 .collect(),
948 };
949 provider.canonical_in_memory_state.update_chain(chain);
950
951 let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
953 let block_count = blocks.len();
954 let canonical_block = blocks.get(block_count - 1).unwrap();
955 let safe_block = blocks.get(block_count - 2).unwrap();
956 let finalized_block = blocks.get(block_count - 3).unwrap();
957
958 provider.set_canonical_head(canonical_block.clone_sealed_header());
960 provider.set_safe(safe_block.clone_sealed_header());
961 provider.set_finalized(finalized_block.clone_sealed_header());
962
963 Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
964 }
965
966 #[expect(clippy::type_complexity)]
967 fn provider_with_random_blocks(
968 rng: &mut impl Rng,
969 database_blocks: usize,
970 in_memory_blocks: usize,
971 block_range_params: BlockRangeParams,
972 ) -> eyre::Result<(
973 BlockchainProvider<MockNodeTypesWithDB>,
974 Vec<SealedBlock<Block>>,
975 Vec<SealedBlock<Block>>,
976 Vec<Vec<Receipt>>,
977 )> {
978 provider_with_chain_spec_and_random_blocks(
979 rng,
980 MAINNET.clone(),
981 database_blocks,
982 in_memory_blocks,
983 block_range_params,
984 )
985 }
986
987 fn persist_block_after_db_tx_creation(
993 provider: BlockchainProvider<MockNodeTypesWithDB>,
994 block_number: BlockNumber,
995 ) {
996 let hook_provider = provider.clone();
997 provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
998 if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
999 state.anchor().number + 1 == block_number
1000 {
1001 let mut lowest_memory_block =
1002 state.parent_state_chain().last().expect("qed").block();
1003 let num_hash = lowest_memory_block.recovered_block().num_hash();
1004
1005 let execution_output = (*lowest_memory_block.execution_output).clone();
1006 lowest_memory_block.execution_output = Arc::new(execution_output);
1007
1008 let provider_rw = hook_provider.database_provider_rw().unwrap();
1010 provider_rw.save_blocks(vec![lowest_memory_block], SaveBlocksMode::Full).unwrap();
1011 provider_rw.commit().unwrap();
1012
1013 hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
1015 }
1016 }));
1017 }
1018
1019 #[test]
1020 fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1021 let mut rng = generators::rng();
1023 let factory = create_test_provider_factory();
1024
1025 let blocks = random_block_range(
1027 &mut rng,
1028 0..=10,
1029 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1030 );
1031 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1032
1033 let provider_rw = factory.provider_rw()?;
1035 for block in database_blocks {
1036 provider_rw.insert_block(
1037 &block.clone().try_recover().expect("failed to seal block with senders"),
1038 )?;
1039 }
1040
1041 provider_rw.commit()?;
1042
1043 let provider = BlockchainProvider::new(factory)?;
1045
1046 let first_db_block = database_blocks.first().unwrap();
1048 let first_in_mem_block = in_memory_blocks.first().unwrap();
1049 let last_in_mem_block = in_memory_blocks.last().unwrap();
1050
1051 assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1053 assert_eq!(
1054 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1055 None
1056 );
1057 assert_eq!(
1059 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1060 None
1061 );
1062
1063 let in_memory_block_senders =
1065 first_in_mem_block.senders().expect("failed to recover senders");
1066 let chain = NewCanonicalChain::Commit {
1067 new: vec![ExecutedBlock {
1068 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1069 first_in_mem_block.clone(),
1070 in_memory_block_senders,
1071 )),
1072 ..Default::default()
1073 }],
1074 };
1075 provider.canonical_in_memory_state.update_chain(chain);
1076
1077 assert_eq!(
1079 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1080 Some(first_in_mem_block.clone().into_block())
1081 );
1082 assert_eq!(
1083 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1084 Some(first_in_mem_block.clone().into_block())
1085 );
1086
1087 assert_eq!(
1089 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1090 Some(first_db_block.clone().into_block())
1091 );
1092 assert_eq!(
1093 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1094 Some(first_db_block.clone().into_block())
1095 );
1096
1097 assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1099
1100 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1102 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1103 last_in_mem_block.clone(),
1104 Default::default(),
1105 )),
1106 ..Default::default()
1107 });
1108
1109 assert_eq!(
1111 provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1112 Some(last_in_mem_block.clone().into_block())
1113 );
1114
1115 Ok(())
1116 }
1117
1118 #[test]
1119 fn test_block_reader_block() -> eyre::Result<()> {
1120 let mut rng = generators::rng();
1122 let factory = create_test_provider_factory();
1123
1124 let blocks = random_block_range(
1126 &mut rng,
1127 0..=10,
1128 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1129 );
1130 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1131
1132 let provider_rw = factory.provider_rw()?;
1134 for block in database_blocks {
1135 provider_rw.insert_block(
1136 &block.clone().try_recover().expect("failed to seal block with senders"),
1137 )?;
1138 }
1139 provider_rw.commit()?;
1140
1141 let provider = BlockchainProvider::new(factory)?;
1143
1144 let first_in_mem_block = in_memory_blocks.first().unwrap();
1146 let first_db_block = database_blocks.first().unwrap();
1148
1149 assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1151 assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1152
1153 let in_memory_block_senders =
1155 first_in_mem_block.senders().expect("failed to recover senders");
1156 let chain = NewCanonicalChain::Commit {
1157 new: vec![ExecutedBlock {
1158 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1159 first_in_mem_block.clone(),
1160 in_memory_block_senders,
1161 )),
1162 ..Default::default()
1163 }],
1164 };
1165 provider.canonical_in_memory_state.update_chain(chain);
1166
1167 assert_eq!(
1169 provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1170 Some(first_in_mem_block.clone().into_block())
1171 );
1172 assert_eq!(
1173 provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1174 Some(first_in_mem_block.clone().into_block())
1175 );
1176
1177 assert_eq!(
1179 provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1180 Some(first_db_block.clone().into_block())
1181 );
1182 assert_eq!(
1183 provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1184 Some(first_db_block.clone().into_block())
1185 );
1186
1187 Ok(())
1188 }
1189
1190 #[test]
1191 fn test_block_reader_pending_block() -> eyre::Result<()> {
1192 let mut rng = generators::rng();
1193 let (provider, _, _, _) = provider_with_random_blocks(
1194 &mut rng,
1195 TEST_BLOCKS_COUNT,
1196 TEST_BLOCKS_COUNT,
1197 BlockRangeParams::default(),
1198 )?;
1199
1200 let mut rng = generators::rng();
1202 let block = random_block(
1203 &mut rng,
1204 0,
1205 BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1206 );
1207
1208 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1210 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1211 block.clone(),
1212 block.senders().unwrap(),
1213 )),
1214 ..Default::default()
1215 });
1216
1217 assert_eq!(
1220 provider.pending_block()?,
1221 Some(RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()))
1222 );
1223
1224 assert_eq!(
1225 provider.pending_block_and_receipts()?,
1226 Some((RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()), vec![]))
1227 );
1228
1229 Ok(())
1230 }
1231
1232 #[test]
1233 fn test_block_body_indices() -> eyre::Result<()> {
1234 let mut rng = generators::rng();
1236 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1237 &mut rng,
1238 TEST_BLOCKS_COUNT,
1239 TEST_BLOCKS_COUNT,
1240 BlockRangeParams {
1241 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1242 ..Default::default()
1243 },
1244 )?;
1245
1246 let first_in_mem_block = in_memory_blocks.first().unwrap();
1247
1248 let in_memory_block_senders =
1250 first_in_mem_block.senders().expect("failed to recover senders");
1251 let chain = NewCanonicalChain::Commit {
1252 new: vec![ExecutedBlock {
1253 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1254 first_in_mem_block.clone(),
1255 in_memory_block_senders,
1256 )),
1257 ..Default::default()
1258 }],
1259 };
1260 provider.canonical_in_memory_state.update_chain(chain);
1261
1262 let first_db_block = database_blocks.first().unwrap().clone();
1263 let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1264
1265 assert_eq!(
1267 provider.block_body_indices(first_db_block.number)?.unwrap(),
1268 StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1269 );
1270
1271 assert_eq!(
1274 provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1275 StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1276 );
1277
1278 let mut rng = rand::rng();
1280 let random_block_number: u64 = rng.random();
1281 assert_eq!(provider.block_body_indices(random_block_number)?, None);
1282
1283 Ok(())
1284 }
1285
1286 #[test]
1287 fn test_block_hash_reader() -> eyre::Result<()> {
1288 let mut rng = generators::rng();
1289 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1290 &mut rng,
1291 TEST_BLOCKS_COUNT,
1292 TEST_BLOCKS_COUNT,
1293 BlockRangeParams::default(),
1294 )?;
1295
1296 let database_block = database_blocks.first().unwrap().clone();
1297 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1298
1299 assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1300 assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1301
1302 assert_eq!(
1303 provider.canonical_hashes_range(0, 10)?,
1304 [database_blocks, in_memory_blocks]
1305 .concat()
1306 .iter()
1307 .map(|block| block.hash())
1308 .collect::<Vec<_>>()
1309 );
1310
1311 Ok(())
1312 }
1313
1314 #[test]
1315 fn test_header_provider() -> eyre::Result<()> {
1316 let mut rng = generators::rng();
1317 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1318 &mut rng,
1319 TEST_BLOCKS_COUNT,
1320 TEST_BLOCKS_COUNT,
1321 BlockRangeParams::default(),
1322 )?;
1323
1324 let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1326 provider.set_finalized(finalized_block.clone_sealed_header());
1327
1328 let blocks = [database_blocks, in_memory_blocks].concat();
1329
1330 assert_eq!(
1331 provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1332 blocks
1333 .iter()
1334 .take_while(|header| header.number <= 8)
1335 .map(|b| b.clone_sealed_header())
1336 .collect::<Vec<_>>()
1337 );
1338
1339 Ok(())
1340 }
1341
1342 #[tokio::test]
1343 async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1344 let factory = create_test_provider_factory();
1345
1346 let mut test_block_builder = TestBlockBuilder::eth();
1348 let block_1 = test_block_builder.generate_random_block(0, B256::ZERO).try_recover()?;
1349 let block_hash_1 = block_1.hash();
1350
1351 let provider_rw = factory.provider_rw()?;
1353 provider_rw.insert_block(&block_1)?;
1354 provider_rw.commit()?;
1355
1356 let provider = BlockchainProvider::new(factory)?;
1357
1358 let in_memory_state = provider.canonical_in_memory_state();
1360 let mut rx_1 = provider.subscribe_to_canonical_state();
1361 let mut rx_2 = provider.subscribe_to_canonical_state();
1362
1363 let block_2 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1365 let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), BTreeMap::new());
1366 let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1367 in_memory_state.notify_canon_state(commit.clone());
1368 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1369 assert_eq!(notification_1, Ok(commit.clone()));
1370 assert_eq!(notification_2, Ok(commit.clone()));
1371
1372 let block_3 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1374 let block_4 = test_block_builder.generate_random_block(2, block_3.hash()).try_recover()?;
1375 let new_chain =
1376 Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), BTreeMap::new());
1377 let re_org =
1378 CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1379 in_memory_state.notify_canon_state(re_org.clone());
1380 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1381 assert_eq!(notification_1, Ok(re_org.clone()));
1382 assert_eq!(notification_2, Ok(re_org.clone()));
1383
1384 Ok(())
1385 }
1386
1387 #[test]
1388 fn test_block_num_reader() -> eyre::Result<()> {
1389 let mut rng = generators::rng();
1390 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1391 &mut rng,
1392 TEST_BLOCKS_COUNT,
1393 TEST_BLOCKS_COUNT,
1394 BlockRangeParams::default(),
1395 )?;
1396
1397 assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1398 assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1399
1400 let database_block = database_blocks.first().unwrap().clone();
1401 let in_memory_block = in_memory_blocks.first().unwrap().clone();
1402 assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1403 assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1404
1405 Ok(())
1406 }
1407
1408 #[test]
1409 fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1410 let mut rng = generators::rng();
1411 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1412 &mut rng,
1413 TEST_BLOCKS_COUNT,
1414 TEST_BLOCKS_COUNT,
1415 BlockRangeParams::default(),
1416 )?;
1417
1418 let database_block = database_blocks.first().unwrap().clone();
1419 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1420
1421 let block_number = database_block.number;
1422 let block_hash = database_block.hash();
1423
1424 assert_eq!(
1425 provider.block_by_id(block_number.into()).unwrap(),
1426 Some(database_block.clone().into_block())
1427 );
1428 assert_eq!(
1429 provider.block_by_id(block_hash.into()).unwrap(),
1430 Some(database_block.into_block())
1431 );
1432
1433 let block_number = in_memory_block.number;
1434 let block_hash = in_memory_block.hash();
1435 assert_eq!(
1436 provider.block_by_id(block_number.into()).unwrap(),
1437 Some(in_memory_block.clone().into_block())
1438 );
1439 assert_eq!(
1440 provider.block_by_id(block_hash.into()).unwrap(),
1441 Some(in_memory_block.into_block())
1442 );
1443
1444 Ok(())
1445 }
1446
1447 #[test]
1448 fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1449 let mut rng = generators::rng();
1450 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1451 &mut rng,
1452 TEST_BLOCKS_COUNT,
1453 TEST_BLOCKS_COUNT,
1454 BlockRangeParams::default(),
1455 )?;
1456
1457 let database_block = database_blocks.first().unwrap().clone();
1458
1459 let in_memory_block_count = in_memory_blocks.len();
1460 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1461 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1462 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1463
1464 let block_number = database_block.number;
1465 assert_eq!(
1466 provider.header_by_number_or_tag(block_number.into()).unwrap(),
1467 Some(database_block.header().clone())
1468 );
1469 assert_eq!(
1470 provider.sealed_header_by_number_or_tag(block_number.into())?,
1471 Some(database_block.clone_sealed_header())
1472 );
1473
1474 assert_eq!(
1475 provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1476 Some(canonical_block.header().clone())
1477 );
1478 assert_eq!(
1479 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1480 Some(canonical_block.clone_sealed_header())
1481 );
1482
1483 assert_eq!(
1484 provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1485 Some(safe_block.header().clone())
1486 );
1487 assert_eq!(
1488 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1489 Some(safe_block.clone_sealed_header())
1490 );
1491
1492 assert_eq!(
1493 provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1494 Some(finalized_block.header().clone())
1495 );
1496 assert_eq!(
1497 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1498 Some(finalized_block.clone_sealed_header())
1499 );
1500
1501 Ok(())
1502 }
1503
1504 #[test]
1505 fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1506 let mut rng = generators::rng();
1507 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1508 &mut rng,
1509 TEST_BLOCKS_COUNT,
1510 TEST_BLOCKS_COUNT,
1511 BlockRangeParams::default(),
1512 )?;
1513
1514 let database_block = database_blocks.first().unwrap().clone();
1515 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1516
1517 let block_number = database_block.number;
1518 let block_hash = database_block.hash();
1519
1520 assert_eq!(
1521 provider.header_by_id(block_number.into()).unwrap(),
1522 Some(database_block.header().clone())
1523 );
1524 assert_eq!(
1525 provider.sealed_header_by_id(block_number.into()).unwrap(),
1526 Some(database_block.clone_sealed_header())
1527 );
1528
1529 assert_eq!(
1530 provider.header_by_id(block_hash.into()).unwrap(),
1531 Some(database_block.header().clone())
1532 );
1533 assert_eq!(
1534 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1535 Some(database_block.clone_sealed_header())
1536 );
1537
1538 let block_number = in_memory_block.number;
1539 let block_hash = in_memory_block.hash();
1540
1541 assert_eq!(
1542 provider.header_by_id(block_number.into()).unwrap(),
1543 Some(in_memory_block.header().clone())
1544 );
1545 assert_eq!(
1546 provider.sealed_header_by_id(block_number.into()).unwrap(),
1547 Some(in_memory_block.clone_sealed_header())
1548 );
1549
1550 assert_eq!(
1551 provider.header_by_id(block_hash.into()).unwrap(),
1552 Some(in_memory_block.header().clone())
1553 );
1554 assert_eq!(
1555 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1556 Some(in_memory_block.clone_sealed_header())
1557 );
1558
1559 Ok(())
1560 }
1561
1562 #[test]
1563 fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
1564 let mut rng = generators::rng();
1565 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1566 &mut rng,
1567 TEST_BLOCKS_COUNT,
1568 TEST_BLOCKS_COUNT,
1569 BlockRangeParams { tx_count: 1..3, ..Default::default() },
1570 )?;
1571
1572 let database_block = database_blocks.first().unwrap().clone();
1573 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1574
1575 let block_number = database_block.number;
1576 let block_hash = database_block.hash();
1577
1578 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1579 assert!(!provider
1580 .receipts_by_number_or_tag(database_block.number.into())?
1581 .unwrap()
1582 .is_empty());
1583
1584 assert_eq!(
1585 provider.receipts_by_block_id(block_number.into())?.unwrap(),
1586 receipts.get(block_number as usize).unwrap().clone()
1587 );
1588 assert_eq!(
1589 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1590 receipts.get(block_number as usize).unwrap().clone()
1591 );
1592
1593 let block_number = in_memory_block.number;
1594 let block_hash = in_memory_block.hash();
1595
1596 assert_eq!(
1597 provider.receipts_by_block_id(block_number.into())?.unwrap(),
1598 receipts.get(block_number as usize).unwrap().clone()
1599 );
1600 assert_eq!(
1601 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1602 receipts.get(block_number as usize).unwrap().clone()
1603 );
1604
1605 Ok(())
1606 }
1607
1608 #[test]
1609 fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
1610 let mut rng = generators::rng();
1611 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1612 &mut rng,
1613 TEST_BLOCKS_COUNT,
1614 TEST_BLOCKS_COUNT,
1615 BlockRangeParams { tx_count: 1..3, ..Default::default() },
1616 )?;
1617
1618 let database_block = database_blocks.first().unwrap().clone();
1619
1620 let in_memory_block_count = in_memory_blocks.len();
1621 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1622 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1623 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1624
1625 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1626 assert!(!provider
1627 .receipts_by_number_or_tag(database_block.number.into())?
1628 .unwrap()
1629 .is_empty());
1630
1631 assert_eq!(
1632 provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
1633 receipts.get(database_block.number as usize).unwrap().clone()
1634 );
1635 assert_eq!(
1636 provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
1637 receipts.get(canonical_block.number as usize).unwrap().clone()
1638 );
1639 assert_eq!(
1640 provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
1641 receipts.get(safe_block.number as usize).unwrap().clone()
1642 );
1643 assert_eq!(
1644 provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
1645 receipts.get(finalized_block.number as usize).unwrap().clone()
1646 );
1647
1648 Ok(())
1649 }
1650
1651 #[test]
1652 fn test_changeset_reader() -> eyre::Result<()> {
1653 let mut rng = generators::rng();
1654
1655 let (database_blocks, in_memory_blocks) =
1656 random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1657
1658 let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1659 let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1660 let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1661
1662 let accounts = random_eoa_accounts(&mut rng, 2);
1663
1664 let (database_changesets, database_state) = random_changeset_range(
1665 &mut rng,
1666 &database_blocks,
1667 accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1668 0..0,
1669 0..0,
1670 );
1671 let (in_memory_changesets, in_memory_state) = random_changeset_range(
1672 &mut rng,
1673 &in_memory_blocks,
1674 database_state
1675 .iter()
1676 .map(|(address, (account, storage))| (*address, (*account, storage.clone()))),
1677 0..0,
1678 0..0,
1679 );
1680
1681 let factory = create_test_provider_factory();
1682
1683 let provider_rw = factory.provider_rw()?;
1684 provider_rw.append_blocks_with_state(
1685 database_blocks
1686 .into_iter()
1687 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1688 .collect(),
1689 &ExecutionOutcome {
1690 bundle: BundleState::new(
1691 database_state.into_iter().map(|(address, (account, _))| {
1692 (address, None, Some(account.into()), Default::default())
1693 }),
1694 database_changesets.iter().map(|block_changesets| {
1695 block_changesets.iter().map(|(address, account, _)| {
1696 (*address, Some(Some((*account).into())), [])
1697 })
1698 }),
1699 Vec::new(),
1700 ),
1701 first_block: first_database_block,
1702 ..Default::default()
1703 },
1704 Default::default(),
1705 )?;
1706 provider_rw.commit()?;
1707
1708 let provider = BlockchainProvider::new(factory)?;
1709
1710 let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1711 let chain = NewCanonicalChain::Commit {
1712 new: vec![in_memory_blocks
1713 .first()
1714 .map(|block| {
1715 let senders = block.senders().expect("failed to recover senders");
1716 ExecutedBlock {
1717 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1718 block.clone(),
1719 senders,
1720 )),
1721 execution_output: Arc::new(BlockExecutionOutput {
1722 state: BundleState::new(
1723 in_memory_state.into_iter().map(|(address, (account, _))| {
1724 (address, None, Some(account.into()), Default::default())
1725 }),
1726 [in_memory_changesets.iter().map(|(address, account, _)| {
1727 (*address, Some(Some((*account).into())), Vec::new())
1728 })],
1729 [],
1730 ),
1731 result: BlockExecutionResult {
1732 receipts: Default::default(),
1733 requests: Default::default(),
1734 gas_used: 0,
1735 blob_gas_used: 0,
1736 },
1737 }),
1738 ..Default::default()
1739 }
1740 })
1741 .unwrap()],
1742 };
1743 provider.canonical_in_memory_state.update_chain(chain);
1744
1745 assert_eq!(
1746 provider.account_block_changeset(last_database_block).unwrap(),
1747 database_changesets
1748 .into_iter()
1749 .next_back()
1750 .unwrap()
1751 .into_iter()
1752 .sorted_by_key(|(address, _, _)| *address)
1753 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1754 .collect::<Vec<_>>()
1755 );
1756 assert_eq!(
1757 provider.account_block_changeset(first_in_memory_block).unwrap(),
1758 in_memory_changesets
1759 .into_iter()
1760 .sorted_by_key(|(address, _, _)| *address)
1761 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1762 .collect::<Vec<_>>()
1763 );
1764
1765 Ok(())
1766 }
1767
1768 #[test]
1769 fn test_state_provider_factory() -> eyre::Result<()> {
1770 let mut rng = generators::rng();
1771
1772 let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
1774 &mut rng,
1775 TEST_BLOCKS_COUNT,
1776 TEST_BLOCKS_COUNT,
1777 BlockRangeParams::default(),
1778 )?;
1779
1780 let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
1782 &mut rng,
1783 TEST_BLOCKS_COUNT,
1784 0,
1785 BlockRangeParams::default(),
1786 )?;
1787
1788 let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
1789 let first_in_memory_block = in_memory_blocks.first().unwrap();
1790 let first_db_block = database_blocks.first().unwrap();
1791
1792 assert_eq!(
1794 first_in_memory_block.hash(),
1795 in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
1796 );
1797 assert_eq!(
1799 first_db_block.hash(),
1800 only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
1801 );
1802
1803 assert_eq!(
1805 first_in_memory_block.hash(),
1806 in_memory_provider
1807 .history_by_block_number(first_in_memory_block.number)?
1808 .block_hash(first_in_memory_block.number)?
1809 .unwrap()
1810 );
1811 assert_eq!(
1812 first_db_block.hash(),
1813 only_database_provider
1814 .history_by_block_number(first_db_block.number)?
1815 .block_hash(first_db_block.number)?
1816 .unwrap()
1817 );
1818 assert_eq!(
1819 first_in_memory_block.hash(),
1820 in_memory_provider
1821 .history_by_block_hash(first_in_memory_block.hash())?
1822 .block_hash(first_in_memory_block.number)?
1823 .unwrap()
1824 );
1825 assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
1826
1827 assert_eq!(
1829 first_in_memory_block.hash(),
1830 in_memory_provider
1831 .state_by_block_hash(first_in_memory_block.hash())?
1832 .block_hash(first_in_memory_block.number)?
1833 .unwrap()
1834 );
1835 assert_eq!(
1836 first_db_block.hash(),
1837 only_database_provider
1838 .state_by_block_hash(first_db_block.hash())?
1839 .block_hash(first_db_block.number)?
1840 .unwrap()
1841 );
1842 assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
1843
1844 assert_eq!(
1846 first_in_memory_block.hash(),
1847 in_memory_provider
1848 .pending()
1849 .unwrap()
1850 .block_hash(first_in_memory_block.number)
1851 .unwrap()
1852 .unwrap()
1853 );
1854
1855 let pending_block = database_blocks[database_blocks.len() - 1].clone();
1857 only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1858 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1859 pending_block.clone(),
1860 Default::default(),
1861 )),
1862 ..Default::default()
1863 });
1864
1865 assert_eq!(
1866 pending_block.hash(),
1867 only_database_provider
1868 .pending()
1869 .unwrap()
1870 .block_hash(pending_block.number)
1871 .unwrap()
1872 .unwrap()
1873 );
1874
1875 assert_eq!(
1876 pending_block.hash(),
1877 only_database_provider
1878 .pending_state_by_hash(pending_block.hash())?
1879 .unwrap()
1880 .block_hash(pending_block.number)?
1881 .unwrap()
1882 );
1883
1884 assert_eq!(
1886 first_in_memory_block.hash(),
1887 in_memory_provider
1888 .state_by_block_number_or_tag(BlockNumberOrTag::Number(
1889 first_in_memory_block.number
1890 ))?
1891 .block_hash(first_in_memory_block.number)?
1892 .unwrap()
1893 );
1894 assert_eq!(
1895 first_in_memory_block.hash(),
1896 in_memory_provider
1897 .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
1898 .block_hash(first_in_memory_block.number)?
1899 .unwrap()
1900 );
1901 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
1903 in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
1904 assert_eq!(
1905 safe_block.hash(),
1906 in_memory_provider
1907 .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
1908 .block_hash(safe_block.number)?
1909 .unwrap()
1910 );
1911 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
1913 in_memory_provider
1914 .canonical_in_memory_state
1915 .set_finalized(finalized_block.clone_sealed_header());
1916 assert_eq!(
1917 finalized_block.hash(),
1918 in_memory_provider
1919 .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
1920 .block_hash(finalized_block.number)?
1921 .unwrap()
1922 );
1923 let earliest_block = blocks.first().unwrap().clone();
1925 assert_eq!(
1926 earliest_block.hash(),
1927 only_database_provider
1928 .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
1929 .block_hash(earliest_block.number)?
1930 .unwrap()
1931 );
1932
1933 Ok(())
1934 }
1935
1936 #[test]
1937 fn test_block_id_reader() -> eyre::Result<()> {
1938 let mut rng = generators::rng();
1940 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
1941 &mut rng,
1942 TEST_BLOCKS_COUNT,
1943 TEST_BLOCKS_COUNT,
1944 BlockRangeParams::default(),
1945 )?;
1946
1947 let pending_block = in_memory_blocks.last().unwrap();
1949 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1950 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1951 pending_block.clone(),
1952 Default::default(),
1953 )),
1954 ..Default::default()
1955 });
1956
1957 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
1959 provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
1960
1961 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
1963 provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
1964
1965 assert_eq!(
1967 provider.pending_block_num_hash()?,
1968 Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
1969 );
1970
1971 assert_eq!(
1973 provider.safe_block_num_hash()?,
1974 Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
1975 );
1976
1977 assert_eq!(
1979 provider.finalized_block_num_hash()?,
1980 Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
1981 );
1982
1983 Ok(())
1984 }
1985
1986 macro_rules! test_by_tx_range {
1987 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
1988
1989 let extra_blocks = [$(stringify!($method)),*].len();
1992
1993 let mut rng = generators::rng();
1994 let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
1995 &mut rng,
1996 TEST_BLOCKS_COUNT,
1997 TEST_BLOCKS_COUNT + extra_blocks,
1998 BlockRangeParams {
1999 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2000 ..Default::default()
2001 },
2002 )?;
2003
2004 $(
2005 let db_tx_count =
2007 database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2008 let in_mem_tx_count =
2009 in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2010
2011 let db_range = 0..=(db_tx_count - 1);
2012 let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
2013
2014 let database_data =
2016 database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2017 assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
2018
2019 let in_memory_data =
2021 in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2022 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
2023
2024 assert_eq!(
2026 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2027 &in_memory_data[1..in_memory_data.len() - 1],
2028 "partial mem data"
2029 );
2030
2031 assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
2033
2034 assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
2036
2037 assert_eq!(
2039 provider.$method(in_mem_range.start() - 2..)?,
2040 database_data[database_data.len() - 2..]
2041 .iter()
2042 .chain(&in_memory_data[..])
2043 .cloned()
2044 .collect::<Vec<_>>(),
2045 "unbounded span data"
2046 );
2047
2048 {
2050 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2052
2053 assert_eq!(
2054 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2055 database_data[database_data.len() - 2..]
2056 .iter()
2057 .chain(&in_memory_data[..in_memory_data.len() - 1])
2058 .cloned()
2059 .collect::<Vec<_>>(),
2060 "span data"
2061 );
2062
2063 database_blocks.push(in_memory_blocks.remove(0));
2065 }
2066
2067 let start_tx_num = u64::MAX;
2069 let end_tx_num = u64::MAX;
2070 let result = provider.$method(start_tx_num..end_tx_num)?;
2071 assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2072
2073 let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2075 assert!(result.is_empty(), "No data should be found for an empty transaction range");
2076 )*
2077 }};
2078 }
2079
2080 #[test]
2081 fn test_methods_by_tx_range() -> eyre::Result<()> {
2082 test_by_tx_range!([
2083 (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2084 .senders()
2085 .unwrap()),
2086 (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2087 .body()
2088 .transactions
2089 .clone()),
2090 (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2091 receipts[block.number as usize].clone()
2092 })
2093 ]);
2094
2095 Ok(())
2096 }
2097
2098 macro_rules! test_by_block_range {
2099 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2100 let extra_blocks = [$(stringify!($method)),*].len();
2103
2104 let mut rng = generators::rng();
2105 let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2106 &mut rng,
2107 TEST_BLOCKS_COUNT,
2108 TEST_BLOCKS_COUNT + extra_blocks,
2109 BlockRangeParams {
2110 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2111 ..Default::default()
2112 },
2113 )?;
2114
2115 $(
2116 let db_block_count = database_blocks.len() as u64;
2118 let in_mem_block_count = in_memory_blocks.len() as u64;
2119
2120 let db_range = 0..=db_block_count - 1;
2121 let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2122
2123 let database_data =
2125 database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2126 assert_eq!(provider.$method(db_range.clone())?, database_data);
2127
2128 let in_memory_data =
2130 in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2131 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2132
2133 assert_eq!(
2135 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2136 &in_memory_data[1..in_memory_data.len() - 1]
2137 );
2138
2139 {
2141
2142 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2144
2145 assert_eq!(
2146 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2147 database_data[database_data.len() - 2..]
2148 .iter()
2149 .chain(&in_memory_data[..in_memory_data.len() - 1])
2150 .cloned()
2151 .collect::<Vec<_>>()
2152 );
2153
2154 database_blocks.push(in_memory_blocks.remove(0));
2156 }
2157
2158 let start_block_num = u64::MAX;
2160 let end_block_num = u64::MAX;
2161 let result = provider.$method(start_block_num..=end_block_num-1)?;
2162 assert!(result.is_empty(), "No data should be found for an invalid block range");
2163
2164 let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2166 assert!(result.is_empty(), "No data should be found for an empty block range");
2167 )*
2168 }};
2169 }
2170
2171 #[test]
2172 fn test_methods_by_block_range() -> eyre::Result<()> {
2173 test_by_block_range!([
2176 (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2177 (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2178 (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2179 (block_with_senders_range, |block: &SealedBlock<Block>| block
2180 .clone()
2181 .try_recover()
2182 .unwrap()),
2183 (recovered_block_range, |block: &SealedBlock<Block>| block
2184 .clone()
2185 .try_recover()
2186 .unwrap()),
2187 (transactions_by_block_range, |block: &SealedBlock<Block>| block
2188 .body()
2189 .transactions
2190 .clone()),
2191 ]);
2192
2193 Ok(())
2194 }
2195
2196 macro_rules! call_method {
2198 ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2199 let result = $provider.$method($($args),*)?;
2200 assert_eq!(
2201 result,
2202 $expected_item,
2203 "{}: item does not match the expected item for arguments {:?}",
2204 stringify!($method),
2205 ($($args),*)
2206 );
2207 }};
2208
2209 (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2211 let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2212 call_method!($provider, $method, (arg), expected_item);
2213 }};
2214
2215 (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2217 let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2218 call_method!($provider, $method, (arg1, arg2), expected_item);
2219 }};
2220 }
2221
2222 macro_rules! test_non_range {
2227 ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2228
2229 let extra_blocks = [$(stringify!($arg_count)),*].len();
2232
2233 let mut rng = generators::rng();
2234 let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2235 &mut rng,
2236 TEST_BLOCKS_COUNT,
2237 TEST_BLOCKS_COUNT + extra_blocks,
2238 BlockRangeParams {
2239 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2240 ..Default::default()
2241 },
2242 )?;
2243
2244 let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2245
2246 $(
2247 let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2248 let tx_num = |block: &SealedBlock<Block>| {
2249 database_blocks
2250 .iter()
2251 .chain(in_memory_blocks.iter())
2252 .take_while(|b| b.number < block.number)
2253 .map(|b| b.transaction_count())
2254 .sum::<usize>() as u64
2255 };
2256
2257 {
2259 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2261
2262 call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2263
2264 database_blocks.push(in_memory_blocks.pop_front().unwrap());
2266 }
2267
2268 let tx_num = |block: &SealedBlock<Block>| {
2270 database_blocks
2271 .iter()
2272 .chain(in_memory_blocks.iter())
2273 .take_while(|b| b.number < block.number)
2274 .map(|b| b.transaction_count())
2275 .sum::<usize>() as u64
2276 };
2277
2278 {
2280 call_method!($arg_count, provider, $method, |_,_,_,_| ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2281 }
2282
2283 {
2285 let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2286
2287 let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2288 call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2289
2290 call_method!($arg_count, provider.database, $method, |_,_,_,_| (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2292 }
2293 )*
2294 }};
2295}
2296
2297 #[test]
2298 fn test_non_range_methods() -> eyre::Result<()> {
2299 let test_tx_index = 0;
2300
2301 test_non_range!([
2302 (
2303 ONE,
2304 header,
2305 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2306 block.hash(),
2307 Some(block.header().clone())
2308 ),
2309 B256::random()
2310 ),
2311 (
2312 ONE,
2313 header_by_number,
2314 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2315 block.number,
2316 Some(block.header().clone())
2317 ),
2318 u64::MAX
2319 ),
2320 (
2321 ONE,
2322 sealed_header,
2323 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2324 block.number,
2325 Some(block.clone_sealed_header())
2326 ),
2327 u64::MAX
2328 ),
2329 (
2330 ONE,
2331 block_hash,
2332 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2333 block.number,
2334 Some(block.hash())
2335 ),
2336 u64::MAX
2337 ),
2338 (
2339 ONE,
2340 block_number,
2341 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2342 block.hash(),
2343 Some(block.number)
2344 ),
2345 B256::random()
2346 ),
2347 (
2348 ONE,
2349 block,
2350 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2351 BlockHashOrNumber::Hash(block.hash()),
2352 Some(block.clone().into_block())
2353 ),
2354 BlockHashOrNumber::Hash(B256::random())
2355 ),
2356 (
2357 ONE,
2358 block,
2359 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2360 BlockHashOrNumber::Number(block.number),
2361 Some(block.clone().into_block())
2362 ),
2363 BlockHashOrNumber::Number(u64::MAX)
2364 ),
2365 (
2366 ONE,
2367 block_body_indices,
2368 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2369 block.number,
2370 Some(StoredBlockBodyIndices {
2371 first_tx_num: tx_num,
2372 tx_count: block.transaction_count() as u64
2373 })
2374 ),
2375 u64::MAX
2376 ),
2377 (
2378 TWO,
2379 recovered_block,
2380 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2381 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2382 block.clone().try_recover().ok()
2383 ),
2384 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2385 ),
2386 (
2387 TWO,
2388 recovered_block,
2389 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2390 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2391 block.clone().try_recover().ok()
2392 ),
2393 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2394 ),
2395 (
2396 TWO,
2397 sealed_block_with_senders,
2398 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2399 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2400 block.clone().try_recover().ok()
2401 ),
2402 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2403 ),
2404 (
2405 TWO,
2406 sealed_block_with_senders,
2407 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2408 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2409 block.clone().try_recover().ok()
2410 ),
2411 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2412 ),
2413 (
2414 ONE,
2415 transaction_id,
2416 |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2417 tx_hash,
2418 Some(tx_num)
2419 ),
2420 B256::random()
2421 ),
2422 (
2423 ONE,
2424 transaction_by_id,
2425 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2426 tx_num,
2427 Some(block.body().transactions[test_tx_index].clone())
2428 ),
2429 u64::MAX
2430 ),
2431 (
2432 ONE,
2433 transaction_by_id_unhashed,
2434 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2435 tx_num,
2436 Some(block.body().transactions[test_tx_index].clone())
2437 ),
2438 u64::MAX
2439 ),
2440 (
2441 ONE,
2442 transaction_by_hash,
2443 |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2444 tx_hash,
2445 Some(block.body().transactions[test_tx_index].clone())
2446 ),
2447 B256::random()
2448 ),
2449 (
2450 ONE,
2451 block_by_transaction_id,
2452 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2453 tx_num,
2454 Some(block.number)
2455 ),
2456 u64::MAX
2457 ),
2458 (
2459 ONE,
2460 transactions_by_block,
2461 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2462 BlockHashOrNumber::Number(block.number),
2463 Some(block.body().transactions.clone())
2464 ),
2465 BlockHashOrNumber::Number(u64::MAX)
2466 ),
2467 (
2468 ONE,
2469 transactions_by_block,
2470 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2471 BlockHashOrNumber::Hash(block.hash()),
2472 Some(block.body().transactions.clone())
2473 ),
2474 BlockHashOrNumber::Number(u64::MAX)
2475 ),
2476 (
2477 ONE,
2478 transaction_sender,
2479 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2480 tx_num,
2481 block.body().transactions[test_tx_index].recover_signer().ok()
2482 ),
2483 u64::MAX
2484 ),
2485 (
2486 ONE,
2487 receipt,
2488 |block: &SealedBlock<Block>,
2489 tx_num: TxNumber,
2490 _: B256,
2491 receipts: &Vec<Vec<Receipt>>| (
2492 tx_num,
2493 Some(receipts[block.number as usize][test_tx_index].clone())
2494 ),
2495 u64::MAX
2496 ),
2497 (
2498 ONE,
2499 receipt_by_hash,
2500 |block: &SealedBlock<Block>,
2501 _: TxNumber,
2502 tx_hash: B256,
2503 receipts: &Vec<Vec<Receipt>>| (
2504 tx_hash,
2505 Some(receipts[block.number as usize][test_tx_index].clone())
2506 ),
2507 B256::random()
2508 ),
2509 (
2510 ONE,
2511 receipts_by_block,
2512 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2513 BlockHashOrNumber::Number(block.number),
2514 Some(receipts[block.number as usize].clone())
2515 ),
2516 BlockHashOrNumber::Number(u64::MAX)
2517 ),
2518 (
2519 ONE,
2520 receipts_by_block,
2521 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2522 BlockHashOrNumber::Hash(block.hash()),
2523 Some(receipts[block.number as usize].clone())
2524 ),
2525 BlockHashOrNumber::Hash(B256::random())
2526 ),
2527 ]);
2529
2530 Ok(())
2531 }
2532
2533 #[test]
2534 fn test_race() -> eyre::Result<()> {
2535 let mut rng = generators::rng();
2536 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2537 &mut rng,
2538 TEST_BLOCKS_COUNT - 1,
2539 TEST_BLOCKS_COUNT + 1,
2540 BlockRangeParams {
2541 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2542 ..Default::default()
2543 },
2544 )?;
2545
2546 let old_transaction_hash_fn =
2549 |hash: B256,
2550 canonical_in_memory_state: CanonicalInMemoryState,
2551 factory: ProviderFactory<MockNodeTypesWithDB>| {
2552 assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2553 Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2554 };
2555
2556 let correct_transaction_hash_fn =
2558 |hash: B256,
2559 canonical_in_memory_state: CanonicalInMemoryState,
2560 _factory: ProviderFactory<MockNodeTypesWithDB>| {
2561 if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
2562 return Ok::<_, ProviderError>(Some(tx));
2563 }
2564 panic!("should not be in database");
2565 };
2567
2568 {
2570 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2573 let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
2574
2575 assert!(matches!(
2578 old_transaction_hash_fn(
2579 *to_be_persisted_tx.tx_hash(),
2580 provider.canonical_in_memory_state(),
2581 provider.database.clone()
2582 ),
2583 Ok(None)
2584 ));
2585 }
2586
2587 {
2589 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
2592 let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
2593
2594 assert_eq!(
2595 correct_transaction_hash_fn(
2596 *to_be_persisted_tx.tx_hash(),
2597 provider.canonical_in_memory_state(),
2598 provider.database
2599 )
2600 .unwrap(),
2601 Some(to_be_persisted_tx)
2602 );
2603 }
2604
2605 Ok(())
2606 }
2607}