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