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