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