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