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