1use crate::{
2 providers::{
3 ConsistentProvider, ProviderNodeTypes, RocksDBProvider, StaticFileProvider,
4 StaticFileProviderRWRefMut,
5 },
6 AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
7 BlockReader, BlockReaderIdExt, BlockSource, CanonChainTracker, CanonStateNotifications,
8 CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader,
9 DatabaseProviderFactory, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader,
10 ReceiptProvider, ReceiptProviderIdExt, RocksDBProviderFactory, StageCheckpointReader,
11 StateProvider, StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory,
12 TransactionVariant, TransactionsProvider,
13};
14use alloy_consensus::{transaction::TransactionMeta, BlockHeader};
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
16use alloy_primitives::{Address, BlockHash, BlockNumber, Bytes, TxHash, TxNumber, B256};
17use alloy_rpc_types_engine::ForkchoiceState;
18use reth_chain_state::{
19 CanonicalInMemoryState, ForkChoiceNotifications, ForkChoiceSubscriptions,
20 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, NodeTypes, NodeTypesWithDB, ReceiptTy, TxTy};
26use reth_primitives_traits::{
27 Account, RecoveredBlock, SealedHeader, SealedOrRecoveredBlock, StorageEntry,
28};
29use reth_prune_types::{PruneCheckpoint, PruneSegment};
30use reth_stages_types::{StageCheckpoint, StageId};
31use reth_static_file_types::StaticFileSegment;
32use reth_storage_api::{
33 BlockBodyIndicesProvider, DatabaseProviderROFactory, NodePrimitivesProvider, RangeEnd,
34 RangeResponse, RangeResult, StateRangeProvider, StateRangeProviderFactory, StateRangeView,
35 StorageChangeSetReader, StorageRangeResult,
36};
37use reth_storage_errors::provider::ProviderResult;
38use reth_storage_overlay::{OverlayStateProvider, OverlayStateProviderFactory, OwnedProvider};
39use reth_trie::{
40 hashed_cursor::{HashedCursor, HashedCursorFactory},
41 metrics::TrieRootMetrics,
42 proof::{Proof, StorageProof},
43 MultiProofTargets, StorageRoot, TrieType,
44};
45use std::{
46 ops::{RangeBounds, RangeInclusive},
47 sync::Arc,
48 time::Instant,
49};
50use tracing::trace;
51
52pub const SNAPSHOT_STATE_RETENTION: u64 = 128;
55
56type StateRangeDbProvider<N> = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
57type HistoricalStateRangeProvider<N> =
58 OverlayStateProvider<OwnedProvider<StateRangeDbProvider<N>>, <N as NodeTypes>::Primitives>;
59
60#[derive(Debug)]
66pub struct BlockchainProvider<N: NodeTypesWithDB> {
67 pub(crate) database: ProviderFactory<N>,
69 pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
72 pub(crate) bal_store: BalStoreHandle,
74}
75
76impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
77 fn clone(&self) -> Self {
78 Self {
79 database: self.database.clone(),
80 canonical_in_memory_state: self.canonical_in_memory_state.clone(),
81 bal_store: self.bal_store.clone(),
82 }
83 }
84}
85
86impl<N: ProviderNodeTypes> BlockchainProvider<N> {
87 pub fn new(storage: ProviderFactory<N>) -> ProviderResult<Self> {
90 let provider = storage.provider()?;
91 let best = provider.chain_info()?;
92 match provider.header_by_number(best.best_number)? {
93 Some(header) => {
94 drop(provider);
95 Ok(Self::with_latest(storage, SealedHeader::new(header, best.best_hash))?)
96 }
97 None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
98 }
99 }
100
101 pub fn with_latest(
107 storage: ProviderFactory<N>,
108 latest: SealedHeader<HeaderTy<N>>,
109 ) -> ProviderResult<Self> {
110 let provider = storage.provider()?;
111 let finalized_header = provider
112 .last_finalized_block_number()?
113 .map(|num| provider.sealed_header(num))
114 .transpose()?
115 .flatten();
116 let safe_header = provider
117 .last_safe_block_number()?
118 .or_else(|| {
119 provider.last_finalized_block_number().ok().flatten()
122 })
123 .map(|num| provider.sealed_header(num))
124 .transpose()?
125 .flatten();
126 let bal_store = storage.bal_store().clone();
127
128 Ok(Self {
129 database: storage,
130 canonical_in_memory_state: CanonicalInMemoryState::with_head(
131 latest,
132 finalized_header,
133 safe_header,
134 ),
135 bal_store,
136 })
137 }
138
139 pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
141 self.canonical_in_memory_state.clone()
142 }
143
144 #[track_caller]
148 pub fn consistent_provider(&self) -> ProviderResult<ConsistentProvider<N>> {
149 ConsistentProvider::new(self.database.clone(), self.canonical_in_memory_state())
150 }
151
152 fn state_provider_at_block_hash(&self, block_hash: B256) -> ProviderResult<StateProviderBox> {
154 let state_provider_factory = OverlayStateProviderFactory::new(
155 self.database.clone(),
156 self.database.overlay_manager().overlay_builder(block_hash),
157 );
158 Ok(Box::new(state_provider_factory.database_provider_ro()?))
159 }
160
161 pub fn state_provider_from_database(
163 &self,
164 provider: StateRangeDbProvider<N>,
165 block_hash: B256,
166 ) -> StateProviderBox {
167 Box::new(OverlayStateProvider::new(
168 provider,
169 self.database.overlay_manager().overlay_builder(block_hash),
170 ))
171 }
172
173 fn block_state_range_provider(
175 &self,
176 state_root: B256,
177 ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
178 let Some(matched) = self
179 .canonical_in_memory_state
180 .canonical_chain()
181 .find(|state| state.state_root() == state_root)
182 else {
183 return Ok(None)
184 };
185
186 let state_provider_factory = OverlayStateProviderFactory::new(
187 self.database.clone(),
188 self.database.overlay_manager().overlay_builder(matched.hash()),
189 );
190 state_provider_factory.database_provider_ro().map(Some)
191 }
192
193 fn historical_state_range_provider(
195 &self,
196 state_root: B256,
197 ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
198 let provider = self.database.provider()?;
199 let Some(finish) = provider.get_stage_checkpoint(StageId::Finish)? else { return Ok(None) };
200 let oldest = finish.block_number.saturating_sub(SNAPSHOT_STATE_RETENTION - 1);
201 let mut block_hash = None;
202
203 for number in (oldest..=finish.block_number).rev() {
204 let Some(header) = provider.sealed_header(number)? else { continue };
205 if header.state_root() == state_root {
206 block_hash = Some(header.hash());
207 break
208 }
209 }
210 drop(provider);
211
212 let Some(block_hash) = block_hash else { return Ok(None) };
213 let state_provider_factory = OverlayStateProviderFactory::new(
214 self.database.clone(),
215 self.database.overlay_manager().overlay_builder(block_hash),
216 );
217 state_provider_factory.database_provider_ro().map(Some)
218 }
219}
220
221impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
222 type Primitives = N::Primitives;
223}
224
225impl<N: ProviderNodeTypes> BalProvider for BlockchainProvider<N> {
226 fn bal_store(&self) -> &BalStoreHandle {
227 &self.bal_store
228 }
229}
230
231struct HistoricalStateRangeView<N: ProviderNodeTypes> {
233 provider: HistoricalStateRangeProvider<N>,
234}
235
236impl<N: ProviderNodeTypes> StateRangeProviderFactory for BlockchainProvider<N> {
237 fn state_range_provider(&self, state_root: B256) -> ProviderResult<Option<StateRangeView>> {
240 let provider = match self.block_state_range_provider(state_root)? {
241 Some(provider) => Some(provider),
242 None => self.historical_state_range_provider(state_root)?,
243 };
244 Ok(provider
245 .map(|provider| Box::new(HistoricalStateRangeView { provider }) as StateRangeView))
246 }
247}
248
249impl<N: ProviderNodeTypes> StateRangeProvider for HistoricalStateRangeView<N> {
250 fn account_range(
251 &self,
252 start: B256,
253 limit: B256,
254 response_bytes: usize,
255 ) -> RangeResult<(B256, Account)> {
256 let mut cursor = self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
257
258 let mut accounts = Vec::new();
259 let mut total_bytes = 0usize;
260 let mut end = RangeEnd::Exhausted;
261
262 let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
265 while let Some((hash, account)) = entry {
266 total_bytes += 32 + 4 * 32; accounts.push((hash, account));
268 if hash >= limit {
269 end = RangeEnd::HashLimit;
270 break
271 }
272 if total_bytes > response_bytes {
273 end = RangeEnd::ByteLimit;
274 break
275 }
276 entry = cursor.next().map_err(ProviderError::Database)?;
277 }
278
279 Ok(RangeResponse { items: accounts, end })
280 }
281
282 fn storage_root_by_hash(&self, hashed_address: B256) -> ProviderResult<B256> {
283 let root = StorageRoot::new_hashed(
284 &self.provider,
285 &self.provider,
286 hashed_address,
287 Default::default(),
288 TrieRootMetrics::new(TrieType::Storage),
289 )
290 .root()
291 .map_err(|err| ProviderError::Database(err.into()))?;
292 Ok(root)
293 }
294
295 fn storage_range(
296 &self,
297 hashed_address: B256,
298 start: B256,
299 limit: B256,
300 response_bytes: usize,
301 ) -> StorageRangeResult {
302 let mut account_cursor =
305 self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
306 let found = account_cursor.seek(hashed_address).map_err(ProviderError::Database)?;
307 if found.map(|(hash, _)| hash) != Some(hashed_address) {
308 return Ok(None)
309 }
310
311 let mut cursor =
312 self.provider.hashed_storage_cursor(hashed_address).map_err(ProviderError::Database)?;
313
314 let mut slots = Vec::new();
315 let mut total_bytes = 0usize;
316 let mut end = RangeEnd::Exhausted;
317
318 let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
321 while let Some((hash, value)) = entry {
322 total_bytes += 64;
323 slots.push((hash, value));
324 if hash >= limit {
325 end = RangeEnd::HashLimit;
326 break
327 }
328 if total_bytes > response_bytes {
329 end = RangeEnd::ByteLimit;
330 break
331 }
332 entry = cursor.next().map_err(ProviderError::Database)?;
333 }
334
335 Ok(Some(RangeResponse { items: slots, end }))
336 }
337
338 fn account_range_proof(&self, keys: &[B256]) -> ProviderResult<Vec<Bytes>> {
339 let multiproof = Proof::new(&self.provider, &self.provider)
340 .multiproof(MultiProofTargets::accounts(keys.iter().copied()))
341 .map_err(ProviderError::from)?;
342 Ok(multiproof
343 .account_subtree
344 .into_nodes_sorted()
345 .into_iter()
346 .map(|(_, bytes)| bytes)
347 .collect())
348 }
349
350 fn storage_range_proof(
351 &self,
352 hashed_address: B256,
353 keys: &[B256],
354 ) -> ProviderResult<Vec<Bytes>> {
355 let multiproof = StorageProof::new_hashed(&self.provider, &self.provider, hashed_address)
356 .storage_multiproof(keys.iter().copied().collect())
357 .map_err(ProviderError::from)?;
358 Ok(multiproof.subtree.into_nodes_sorted().into_iter().map(|(_, bytes)| bytes).collect())
359 }
360}
361
362impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
363 type DB = N::DB;
364 type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
365 type ProviderRW = <ProviderFactory<N> as DatabaseProviderFactory>::ProviderRW;
366
367 fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
368 DatabaseProviderFactory::database_provider_ro(&self.database)
369 }
370
371 fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
372 DatabaseProviderFactory::database_provider_rw(&self.database)
373 }
374}
375
376impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
377 fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
378 self.database.static_file_provider()
379 }
380
381 fn get_static_file_writer(
382 &self,
383 block: BlockNumber,
384 segment: StaticFileSegment,
385 ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
386 self.database.get_static_file_writer(block, segment)
387 }
388}
389
390impl<N: ProviderNodeTypes> RocksDBProviderFactory for BlockchainProvider<N> {
391 fn rocksdb_provider(&self) -> RocksDBProvider {
392 self.database.rocksdb_provider()
393 }
394
395 fn set_pending_rocksdb_batch(&self, _batch: rocksdb::WriteBatchWithTransaction<true>) {
396 unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::set_pending_rocksdb_batch instead")
397 }
398
399 fn commit_pending_rocksdb_batches(&self) -> ProviderResult<()> {
400 unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::commit_pending_rocksdb_batches instead")
401 }
402}
403
404impl<N: ProviderNodeTypes> HeaderProvider for BlockchainProvider<N> {
405 type Header = HeaderTy<N>;
406
407 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
408 self.consistent_provider()?.header(block_hash)
409 }
410
411 fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
412 self.consistent_provider()?.header_by_number(num)
413 }
414
415 fn headers_range(
416 &self,
417 range: impl RangeBounds<BlockNumber>,
418 ) -> ProviderResult<Vec<Self::Header>> {
419 self.consistent_provider()?.headers_range(range)
420 }
421
422 fn sealed_header(
423 &self,
424 number: BlockNumber,
425 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
426 self.consistent_provider()?.sealed_header(number)
427 }
428
429 fn sealed_headers_range(
430 &self,
431 range: impl RangeBounds<BlockNumber>,
432 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
433 self.consistent_provider()?.sealed_headers_range(range)
434 }
435
436 fn sealed_headers_while(
437 &self,
438 range: impl RangeBounds<BlockNumber>,
439 predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
440 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
441 self.consistent_provider()?.sealed_headers_while(range, predicate)
442 }
443}
444
445impl<N: ProviderNodeTypes> BlockHashReader for BlockchainProvider<N> {
446 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
447 self.consistent_provider()?.block_hash(number)
448 }
449
450 fn canonical_hashes_range(
451 &self,
452 start: BlockNumber,
453 end: BlockNumber,
454 ) -> ProviderResult<Vec<B256>> {
455 self.consistent_provider()?.canonical_hashes_range(start, end)
456 }
457}
458
459impl<N: ProviderNodeTypes> BlockNumReader for BlockchainProvider<N> {
460 fn chain_info(&self) -> ProviderResult<ChainInfo> {
461 Ok(self.canonical_in_memory_state.chain_info())
462 }
463
464 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
465 Ok(self.canonical_in_memory_state.get_canonical_block_number())
466 }
467
468 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
469 self.database.last_block_number()
470 }
471
472 fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
473 self.database.earliest_block_number()
474 }
475
476 fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
477 self.consistent_provider()?.block_number(hash)
478 }
479}
480
481impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
482 fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
483 Ok(self.canonical_in_memory_state.pending_block_num_hash())
484 }
485
486 fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
487 Ok(self.canonical_in_memory_state.get_safe_num_hash())
488 }
489
490 fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
491 Ok(self.canonical_in_memory_state.get_finalized_num_hash())
492 }
493}
494
495impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
496 type Block = BlockTy<N>;
497
498 fn find_block_by_hash(
499 &self,
500 hash: B256,
501 source: BlockSource,
502 ) -> ProviderResult<Option<Self::Block>> {
503 self.consistent_provider()?.find_block_by_hash(hash, source)
504 }
505
506 fn find_sealed_or_recovered_block(
507 &self,
508 hash: B256,
509 source: BlockSource,
510 ) -> ProviderResult<Option<SealedOrRecoveredBlock<Self::Block>>> {
511 self.consistent_provider()?.find_sealed_or_recovered_block(hash, source)
512 }
513
514 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
515 self.consistent_provider()?.block(id)
516 }
517
518 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
519 Ok(self.canonical_in_memory_state.pending_recovered_block())
520 }
521
522 fn pending_block_and_receipts(
523 &self,
524 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
525 Ok(self.canonical_in_memory_state.pending_block_and_receipts())
526 }
527
528 fn recovered_block(
535 &self,
536 id: BlockHashOrNumber,
537 transaction_kind: TransactionVariant,
538 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
539 self.consistent_provider()?.recovered_block(id, transaction_kind)
540 }
541
542 fn sealed_block_with_senders(
543 &self,
544 id: BlockHashOrNumber,
545 transaction_kind: TransactionVariant,
546 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
547 self.consistent_provider()?.sealed_block_with_senders(id, transaction_kind)
548 }
549
550 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
551 self.consistent_provider()?.block_range(range)
552 }
553
554 fn block_with_senders_range(
555 &self,
556 range: RangeInclusive<BlockNumber>,
557 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
558 self.consistent_provider()?.block_with_senders_range(range)
559 }
560
561 fn recovered_block_range(
562 &self,
563 range: RangeInclusive<BlockNumber>,
564 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
565 self.consistent_provider()?.recovered_block_range(range)
566 }
567
568 fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
569 self.consistent_provider()?.block_by_transaction_id(id)
570 }
571}
572
573impl<N: ProviderNodeTypes> TransactionsProvider for BlockchainProvider<N> {
574 type Transaction = TxTy<N>;
575
576 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
577 self.consistent_provider()?.transaction_id(tx_hash)
578 }
579
580 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
581 self.consistent_provider()?.transaction_by_id(id)
582 }
583
584 fn transaction_by_id_unhashed(
585 &self,
586 id: TxNumber,
587 ) -> ProviderResult<Option<Self::Transaction>> {
588 self.consistent_provider()?.transaction_by_id_unhashed(id)
589 }
590
591 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
592 self.consistent_provider()?.transaction_by_hash(hash)
593 }
594
595 fn transaction_by_hash_with_meta(
596 &self,
597 tx_hash: TxHash,
598 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
599 self.consistent_provider()?.transaction_by_hash_with_meta(tx_hash)
600 }
601
602 fn transactions_by_block(
603 &self,
604 id: BlockHashOrNumber,
605 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
606 self.consistent_provider()?.transactions_by_block(id)
607 }
608
609 fn transactions_by_block_range(
610 &self,
611 range: impl RangeBounds<BlockNumber>,
612 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
613 self.consistent_provider()?.transactions_by_block_range(range)
614 }
615
616 fn transactions_by_tx_range(
617 &self,
618 range: impl RangeBounds<TxNumber>,
619 ) -> ProviderResult<Vec<Self::Transaction>> {
620 self.consistent_provider()?.transactions_by_tx_range(range)
621 }
622
623 fn senders_by_tx_range(
624 &self,
625 range: impl RangeBounds<TxNumber>,
626 ) -> ProviderResult<Vec<Address>> {
627 self.consistent_provider()?.senders_by_tx_range(range)
628 }
629
630 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
631 self.consistent_provider()?.transaction_sender(id)
632 }
633}
634
635impl<N: ProviderNodeTypes> ReceiptProvider for BlockchainProvider<N> {
636 type Receipt = ReceiptTy<N>;
637
638 fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
639 self.consistent_provider()?.receipt(id)
640 }
641
642 fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
643 self.consistent_provider()?.receipt_by_hash(hash)
644 }
645
646 fn receipts_by_block(
647 &self,
648 block: BlockHashOrNumber,
649 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
650 self.consistent_provider()?.receipts_by_block(block)
651 }
652
653 fn receipts_by_tx_range(
654 &self,
655 range: impl RangeBounds<TxNumber>,
656 ) -> ProviderResult<Vec<Self::Receipt>> {
657 self.consistent_provider()?.receipts_by_tx_range(range)
658 }
659
660 fn receipts_by_block_range(
661 &self,
662 block_range: RangeInclusive<BlockNumber>,
663 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
664 self.consistent_provider()?.receipts_by_block_range(block_range)
665 }
666}
667
668impl<N: ProviderNodeTypes> ReceiptProviderIdExt for BlockchainProvider<N> {
669 fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
670 self.consistent_provider()?.receipts_by_block_id(block)
671 }
672}
673
674impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for BlockchainProvider<N> {
675 fn block_body_indices(
676 &self,
677 number: BlockNumber,
678 ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
679 self.consistent_provider()?.block_body_indices(number)
680 }
681
682 fn block_body_indices_range(
683 &self,
684 range: RangeInclusive<BlockNumber>,
685 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
686 self.consistent_provider()?.block_body_indices_range(range)
687 }
688}
689
690impl<N: ProviderNodeTypes> StageCheckpointReader for BlockchainProvider<N> {
691 fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
692 self.consistent_provider()?.get_stage_checkpoint(id)
693 }
694
695 fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
696 self.consistent_provider()?.get_stage_checkpoint_progress(id)
697 }
698
699 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
700 self.consistent_provider()?.get_all_checkpoints()
701 }
702}
703
704impl<N: ProviderNodeTypes> PruneCheckpointReader for BlockchainProvider<N> {
705 fn get_prune_checkpoint(
706 &self,
707 segment: PruneSegment,
708 ) -> ProviderResult<Option<PruneCheckpoint>> {
709 self.consistent_provider()?.get_prune_checkpoint(segment)
710 }
711
712 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
713 self.consistent_provider()?.get_prune_checkpoints()
714 }
715}
716
717impl<N: NodeTypesWithDB> ChainSpecProvider for BlockchainProvider<N> {
718 type ChainSpec = N::ChainSpec;
719
720 fn chain_spec(&self) -> Arc<N::ChainSpec> {
721 self.database.chain_spec()
722 }
723}
724
725impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider<N> {
726 fn latest(&self) -> ProviderResult<StateProviderBox> {
728 trace!(target: "providers::blockchain", "Getting latest block state provider");
729 if let Some(state) = self.canonical_in_memory_state.head_state() {
731 trace!(target: "providers::blockchain", "Using head state for latest state provider");
732 self.state_provider_at_block_hash(state.hash())
733 } else {
734 trace!(target: "providers::blockchain", "Using database state for latest state provider");
735 self.database.latest()
736 }
737 }
738
739 fn state_by_block_number_or_tag(
741 &self,
742 number_or_tag: BlockNumberOrTag,
743 ) -> ProviderResult<StateProviderBox> {
744 match number_or_tag {
745 BlockNumberOrTag::Latest => self.latest(),
746 BlockNumberOrTag::Finalized => {
747 let hash =
749 self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
750 self.state_by_block_hash(hash)
751 }
752 BlockNumberOrTag::Safe => {
753 let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
755 self.state_by_block_hash(hash)
756 }
757 BlockNumberOrTag::Earliest => {
758 self.history_by_block_number(self.earliest_block_number()?)
759 }
760 BlockNumberOrTag::Pending => self.pending(),
761 BlockNumberOrTag::Number(num) => {
762 let hash = self
763 .block_hash(num)?
764 .ok_or_else(|| ProviderError::HeaderNotFound(num.into()))?;
765 self.state_by_block_hash(hash)
766 }
767 }
768 }
769
770 fn history_by_block_number(
771 &self,
772 block_number: BlockNumber,
773 ) -> ProviderResult<StateProviderBox> {
774 trace!(target: "providers::blockchain", ?block_number, "Getting history by block number");
775 let provider = self.consistent_provider()?;
776 let hash = provider
777 .block_hash(block_number)?
778 .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
779 Ok(self.state_provider_from_database(provider.into_database_provider(), hash))
780 }
781
782 fn history_by_block_hash(&self, block_hash: BlockHash) -> ProviderResult<StateProviderBox> {
783 trace!(target: "providers::blockchain", ?block_hash, "Getting history by block hash");
784 let provider = self.consistent_provider()?;
785 provider.block_number(block_hash)?.ok_or(ProviderError::BlockHashNotFound(block_hash))?;
786 Ok(self.state_provider_from_database(provider.into_database_provider(), block_hash))
787 }
788
789 fn state_by_block_hash(&self, hash: BlockHash) -> ProviderResult<StateProviderBox> {
790 trace!(target: "providers::blockchain", ?hash, "Getting state by block hash");
791 if let Some(state) = self.canonical_in_memory_state.state_by_hash(hash) {
792 self.state_provider_at_block_hash(state.hash())
793 } else if let Ok(state) = self.history_by_block_hash(hash) {
794 Ok(state)
796 } else if let Ok(Some(pending)) = self.pending_state_by_hash(hash) {
797 Ok(pending)
799 } else {
800 Err(ProviderError::StateForHashNotFound(hash))
802 }
803 }
804
805 fn pending(&self) -> ProviderResult<StateProviderBox> {
810 trace!(target: "providers::blockchain", "Getting provider for pending state");
811
812 if let Some(pending) = self.canonical_in_memory_state.pending_state() {
813 return self.state_provider_at_block_hash(pending.hash());
815 }
816
817 self.latest()
819 }
820
821 fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
822 if let Some(pending) = self.canonical_in_memory_state.pending_state() &&
823 pending.hash() == block_hash
824 {
825 return self.state_provider_at_block_hash(pending.hash()).map(Some);
826 }
827 Ok(None)
828 }
829
830 fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
831 if let Some(pending) = self.canonical_in_memory_state.pending_state() {
832 return self.state_provider_at_block_hash(pending.hash()).map(Some)
833 }
834
835 Ok(None)
836 }
837}
838
839impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider<N> {
840 type Header = HeaderTy<N>;
841
842 fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
843 self.canonical_in_memory_state.on_forkchoice_update_received();
845 }
846
847 fn last_received_update_timestamp(&self) -> Option<Instant> {
848 self.canonical_in_memory_state.last_received_update_timestamp()
849 }
850
851 fn set_canonical_head(&self, header: SealedHeader<Self::Header>) {
852 self.canonical_in_memory_state.set_canonical_head(header);
853 }
854
855 fn set_safe(&self, header: SealedHeader<Self::Header>) {
856 self.canonical_in_memory_state.set_safe(header);
857 }
858
859 fn set_finalized(&self, header: SealedHeader<Self::Header>) {
860 self.canonical_in_memory_state.set_finalized(header);
861 }
862}
863
864impl<N: ProviderNodeTypes> BlockReaderIdExt for BlockchainProvider<N>
865where
866 Self: ReceiptProviderIdExt,
867{
868 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
869 self.consistent_provider()?.block_by_id(id)
870 }
871
872 fn header_by_number_or_tag(
873 &self,
874 id: BlockNumberOrTag,
875 ) -> ProviderResult<Option<Self::Header>> {
876 self.consistent_provider()?.header_by_number_or_tag(id)
877 }
878
879 fn sealed_header_by_number_or_tag(
880 &self,
881 id: BlockNumberOrTag,
882 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
883 self.consistent_provider()?.sealed_header_by_number_or_tag(id)
884 }
885
886 fn sealed_header_by_id(
887 &self,
888 id: BlockId,
889 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
890 self.consistent_provider()?.sealed_header_by_id(id)
891 }
892
893 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
894 self.consistent_provider()?.header_by_id(id)
895 }
896}
897
898impl<N: ProviderNodeTypes> CanonStateSubscriptions for BlockchainProvider<N> {
899 fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<Self::Primitives> {
900 self.canonical_in_memory_state.subscribe_canon_state()
901 }
902}
903
904impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider<N> {
905 type Header = HeaderTy<N>;
906
907 fn subscribe_safe_block(&self) -> ForkChoiceNotifications<Self::Header> {
908 let receiver = self.canonical_in_memory_state.subscribe_safe_block();
909 ForkChoiceNotifications(receiver)
910 }
911
912 fn subscribe_finalized_block(&self) -> ForkChoiceNotifications<Self::Header> {
913 let receiver = self.canonical_in_memory_state.subscribe_finalized_block();
914 ForkChoiceNotifications(receiver)
915 }
916}
917
918impl<N: ProviderNodeTypes> PersistedBlockSubscriptions for BlockchainProvider<N> {
919 fn subscribe_persisted_block(&self) -> PersistedBlockNotifications {
920 let receiver = self.canonical_in_memory_state.subscribe_persisted_block();
921 PersistedBlockNotifications(receiver)
922 }
923}
924
925impl<N: ProviderNodeTypes> StorageChangeSetReader for BlockchainProvider<N> {
926 fn storage_changeset(
927 &self,
928 block_number: BlockNumber,
929 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
930 self.consistent_provider()?.storage_changeset(block_number)
931 }
932
933 fn get_storage_before_block(
934 &self,
935 block_number: BlockNumber,
936 address: Address,
937 storage_key: B256,
938 ) -> ProviderResult<Option<StorageEntry>> {
939 self.consistent_provider()?.get_storage_before_block(block_number, address, storage_key)
940 }
941
942 fn storage_changesets_range(
943 &self,
944 range: impl RangeBounds<BlockNumber>,
945 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
946 self.consistent_provider()?.storage_changesets_range(range)
947 }
948}
949
950impl<N: ProviderNodeTypes> ChangeSetReader for BlockchainProvider<N> {
951 fn account_block_changeset(
952 &self,
953 block_number: BlockNumber,
954 ) -> ProviderResult<Vec<AccountBeforeTx>> {
955 self.consistent_provider()?.account_block_changeset(block_number)
956 }
957
958 fn get_account_before_block(
959 &self,
960 block_number: BlockNumber,
961 address: Address,
962 ) -> ProviderResult<Option<AccountBeforeTx>> {
963 self.consistent_provider()?.get_account_before_block(block_number, address)
964 }
965
966 fn account_changesets_range(
967 &self,
968 range: impl core::ops::RangeBounds<BlockNumber>,
969 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
970 self.consistent_provider()?.account_changesets_range(range)
971 }
972}
973
974impl<N: ProviderNodeTypes> StateReader for BlockchainProvider<N> {
975 type Receipt = ReceiptTy<N>;
976
977 fn get_state(
987 &self,
988 block: BlockNumber,
989 ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
990 if let Some(head) = self.canonical_in_memory_state.head_state() &&
991 let Some(state) = head.block_on_chain(block.into())
992 {
993 return Ok(Some(ExecutionOutcome::from((
994 state.block_ref().execution_outcome().clone(),
995 block,
996 ))))
997 }
998
999 let provider = self.database.provider()?;
1000 let Some(block_body) = provider.block_body_indices(block)? else { return Ok(None) };
1001
1002 let from_transaction_num = block_body.first_tx_num();
1003 let to_transaction_num = block_body.last_tx_num();
1004 let account_changeset = provider.account_changesets_range(block..=block)?;
1005 let storage_changeset = provider.storage_changeset(block)?;
1006
1007 let Some(block_hash) = provider.block_hash(block)? else { return Ok(None) };
1008 let state_provider = OverlayStateProvider::<&_, N::Primitives>::new_ref(
1009 &provider,
1010 self.database.overlay_manager().overlay_builder(block_hash),
1011 );
1012 let (state, reverts) = provider.populate_bundle_state(
1013 account_changeset,
1014 storage_changeset,
1015 |address| state_provider.basic_account(&address),
1016 |address, storage_key| state_provider.storage(address, storage_key),
1017 )?;
1018 let receipts = provider.receipts_by_tx_range(from_transaction_num..=to_transaction_num)?;
1019
1020 Ok(Some(ExecutionOutcome::new_init(
1021 state,
1022 reverts,
1023 Vec::new(),
1025 vec![receipts],
1026 block,
1027 Vec::new(),
1028 )))
1029 }
1030}
1031
1032#[cfg(test)]
1033mod tests {
1034 use super::SNAPSHOT_STATE_RETENTION;
1035 use crate::{
1036 providers::BlockchainProvider,
1037 test_utils::{
1038 create_test_provider_factory, create_test_provider_factory_with_chain_spec,
1039 MockNodeTypesWithDB,
1040 },
1041 BlockWriter, CanonChainTracker, ProviderFactory, SaveBlocksInput,
1042 };
1043 use alloy_consensus::constants::EMPTY_ROOT_HASH;
1044 use alloy_eips::{BlockHashOrNumber, BlockNumHash, BlockNumberOrTag};
1045 use alloy_primitives::{keccak256, Address, BlockNumber, TxNumber, B256, U256};
1046 use itertools::Itertools;
1047 use rand::Rng;
1048 use reth_chain_state::{
1049 test_utils::TestBlockBuilder, CanonStateNotification, CanonStateSubscriptions,
1050 CanonicalInMemoryState, ExecutedBlock, NewCanonicalChain,
1051 };
1052 use reth_chainspec::{ChainSpec, MAINNET};
1053 use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
1054 use reth_errors::ProviderError;
1055 use reth_ethereum_primitives::{Block, Receipt};
1056 use reth_execution_types::{
1057 BlockExecutionOutput, BlockExecutionResult, Chain, ExecutionOutcome,
1058 };
1059 use reth_primitives_traits::{
1060 Account, Block as _, RecoveredBlock, SealedBlock, SignerRecoverable, StorageEntry,
1061 };
1062 use reth_stages_types::{StageCheckpoint, StageId};
1063 use reth_storage_api::{
1064 BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader,
1065 BlockReaderIdExt, BlockSource, ChangeSetReader, DBProvider, DatabaseProviderFactory,
1066 HashingWriter, HeaderProvider, RangeEnd, ReceiptProvider, ReceiptProviderIdExt,
1067 StageCheckpointWriter, StateProviderFactory, StateRangeProvider, StateRangeProviderFactory,
1068 StateRootProvider, StateWriteConfig, StateWriter, StorageRootProvider, TransactionVariant,
1069 TransactionsProvider,
1070 };
1071 use reth_testing_utils::generators::{
1072 self, random_block, random_block_range, random_changeset_range, random_eoa_accounts,
1073 random_receipt, BlockParams, BlockRangeParams,
1074 };
1075 use reth_trie::{updates::TrieUpdates, ComputedTrieData, HashedPostState, HashedStorage};
1076 use revm::database::{BundleState, OriginalValuesKnown};
1077 use std::{
1078 collections::{BTreeMap, HashMap},
1079 ops::{Bound, Range, RangeBounds},
1080 sync::Arc,
1081 };
1082
1083 #[test]
1084 fn historical_proofs_complete_masked_trie_rows() -> eyre::Result<()> {
1085 use crate::{StaticFileProviderFactory, StaticFileSegment, StaticFileWriter};
1086 use reth_storage_api::{StorageSettings, StorageSettingsCache, TrieWriter};
1087 use reth_trie::{test_utils::TrieTestHarness, MultiProofTargetsV2};
1088 use revm::state::AccountInfo;
1089
1090 let address = Address::with_last_byte(1);
1091 let other_address = Address::with_last_byte(2);
1092 let hashed_address = keccak256(address);
1093 let account = Account { balance: U256::from(1), ..Default::default() };
1094 let slots: Vec<B256> = (0..=2u8)
1097 .flat_map(|prefix| {
1098 (0..u64::MAX)
1099 .map(|slot| B256::from(U256::from(slot)))
1100 .filter(move |slot| keccak256(slot)[0] == prefix)
1101 .take(2)
1102 })
1103 .collect();
1104 let mut storage: BTreeMap<_, _> = slots.iter().map(|&slot| (slot, U256::from(1))).collect();
1105 let mut trie = TrieTestHarness::new(
1106 storage.iter().map(|(slot, value)| (keccak256(slot), *value)).collect(),
1107 );
1108 let mut blocks = Vec::<ExecutedBlock>::new();
1109 let mut storage_roots = Vec::new();
1110 for number in 0..=2 {
1111 let mut output = (*ExecutedBlock::<reth_ethereum_primitives::EthPrimitives>::default()
1112 .execution_output)
1113 .clone();
1114 let (state, storage_updates) = if number == 0 {
1115 (
1116 HashedPostState::default()
1117 .with_accounts([
1118 (hashed_address, Some(account)),
1119 (keccak256(other_address), Some(account)),
1120 ])
1121 .with_storages([(
1122 hashed_address,
1123 HashedStorage::from_iter(trie.storage().iter().map(|(k, v)| (*k, *v))),
1124 )]),
1125 trie.storage_trie_updates().clone(),
1126 )
1127 } else {
1128 let slot = slots[(number as usize - 1) * 2];
1129 let value = U256::from(number + 1);
1130 let changes = BTreeMap::from([(keccak256(slot), value)]);
1131 let (_, updates) = trie.get_root_with_updates(&changes);
1132 trie.apply_changeset(changes);
1133 storage.insert(slot, value);
1134 let info = AccountInfo::from_balance(account.balance);
1135 output.state = BundleState::builder(number..=number)
1136 .state_original_account_info(address, info.clone())
1137 .state_present_account_info(address, info)
1138 .state_storage(
1139 address,
1140 std::iter::once((U256::from_be_bytes(slot.0), (U256::from(1), value)))
1141 .collect(),
1142 )
1143 .revert_storage(
1144 number,
1145 address,
1146 vec![(U256::from_be_bytes(slot.0), U256::from(1))],
1147 )
1148 .build();
1149 (
1150 HashedPostState::from_hashed_storage(
1151 hashed_address,
1152 HashedStorage::from_iter([(keccak256(slot), value)]),
1153 ),
1154 updates,
1155 )
1156 };
1157 let mut updates = TrieUpdates::default();
1158 updates.storage_tries.insert(hashed_address, storage_updates);
1159 let state_root = reth_trie::test_utils::state_root([
1160 (address, (account, storage.clone())),
1161 (other_address, (account, BTreeMap::new())),
1162 ]);
1163 storage_roots.push(reth_trie::test_utils::storage_root(storage.clone()));
1164 let block = Block {
1165 header: alloy_consensus::Header {
1166 number,
1167 parent_hash: blocks
1168 .last()
1169 .map(|b| b.recovered_block().hash())
1170 .unwrap_or_default(),
1171 state_root,
1172 ..Default::default()
1173 },
1174 ..Default::default()
1175 };
1176 blocks.push(ExecutedBlock::new(
1177 Arc::new(RecoveredBlock::new_unhashed(block, vec![])),
1178 Arc::new(output),
1179 ComputedTrieData::new(
1180 Arc::new(state.into_sorted()),
1181 Arc::new(updates.into_sorted()),
1182 ),
1183 ));
1184 }
1185
1186 let factory = create_test_provider_factory();
1187 factory.set_storage_settings_cache(StorageSettings::v2());
1188 let writer = factory.provider_rw()?;
1189 writer.insert_block(blocks[0].recovered_block())?;
1190 writer.write_hashed_state(blocks[0].hashed_state_ref())?;
1191 writer.write_trie_updates_sorted(blocks[0].trie_updates_ref())?;
1192 writer.commit()?;
1193 let static_files = factory.static_file_provider();
1194 static_files.get_writer(0, StaticFileSegment::Receipts)?.increment_block(0)?;
1195 static_files
1196 .get_writer(0, StaticFileSegment::AccountChangeSets)?
1197 .append_account_changeset(vec![], 0)?;
1198 static_files
1199 .get_writer(0, StaticFileSegment::StorageChangeSets)?
1200 .append_storage_changeset(vec![], 0)?;
1201 static_files.commit()?;
1202 let writer = factory.provider_rw()?;
1203 writer.save_blocks(&SaveBlocksInput::new(blocks[1..].to_vec(), 0, 0, 2, 1))?;
1204 writer.commit()?;
1205 factory.overlay_manager().insert_block(blocks[2].clone());
1206 let provider = BlockchainProvider::new(factory)?;
1207
1208 for number in [1, 2] {
1209 let state = provider.history_by_block_hash(blocks[number].recovered_block().hash())?;
1210 let root = blocks[number].recovered_block().state_root;
1211 state
1212 .multiproof_v2(
1213 Default::default(),
1214 MultiProofTargetsV2 {
1215 account_targets: vec![keccak256(other_address).into()],
1216 ..Default::default()
1217 },
1218 )?
1219 .account_proof(other_address, &[])?
1220 .verify(root)?;
1221 assert_eq!(state.state_root(HashedPostState::default())?, root);
1222 assert_eq!(
1223 state.storage_root(address, HashedStorage::default())?,
1224 storage_roots[number]
1225 );
1226 state
1227 .storage_proof(address, slots[2], HashedStorage::default())?
1228 .verify(storage_roots[number])?;
1229 let proof = state.storage_multiproof(address, &[slots[2]], HashedStorage::default())?;
1230 assert_eq!(proof.root, storage_roots[number]);
1231 proof.storage_proof(slots[2])?.verify(storage_roots[number])?;
1232 }
1233 Ok(())
1234 }
1235
1236 const TEST_BLOCKS_COUNT: usize = 5;
1237
1238 const TEST_TRANSACTIONS_COUNT: u8 = 4;
1239
1240 fn random_blocks(
1241 rng: &mut impl Rng,
1242 database_blocks: usize,
1243 in_memory_blocks: usize,
1244 requests_count: Option<Range<u8>>,
1245 withdrawals_count: Option<Range<u8>>,
1246 tx_count: impl RangeBounds<u8>,
1247 ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1248 let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1249
1250 let tx_start = match tx_count.start_bound() {
1251 Bound::Included(&n) | Bound::Excluded(&n) => n,
1252 Bound::Unbounded => u8::MIN,
1253 };
1254 let tx_end = match tx_count.end_bound() {
1255 Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1256 Bound::Unbounded => u8::MAX,
1257 };
1258
1259 let blocks = random_block_range(
1260 rng,
1261 0..=block_range,
1262 BlockRangeParams {
1263 parent: Some(B256::ZERO),
1264 tx_count: tx_start..tx_end,
1265 requests_count,
1266 withdrawals_count,
1267 },
1268 );
1269 let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1270 (database_blocks.to_vec(), in_memory_blocks.to_vec())
1271 }
1272
1273 #[expect(clippy::type_complexity)]
1274 fn provider_with_chain_spec_and_random_blocks(
1275 rng: &mut impl Rng,
1276 chain_spec: Arc<ChainSpec>,
1277 database_blocks: usize,
1278 in_memory_blocks: usize,
1279 block_range_params: BlockRangeParams,
1280 ) -> eyre::Result<(
1281 BlockchainProvider<MockNodeTypesWithDB>,
1282 Vec<SealedBlock<Block>>,
1283 Vec<SealedBlock<Block>>,
1284 Vec<Vec<Receipt>>,
1285 )> {
1286 let (database_blocks, in_memory_blocks) = random_blocks(
1287 rng,
1288 database_blocks,
1289 in_memory_blocks,
1290 block_range_params.requests_count,
1291 block_range_params.withdrawals_count,
1292 block_range_params.tx_count,
1293 );
1294
1295 let receipts: Vec<Vec<_>> = database_blocks
1296 .iter()
1297 .chain(in_memory_blocks.iter())
1298 .map(|block| block.body().transactions.iter())
1299 .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
1300 .collect();
1301
1302 let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1303 let provider_rw = factory.database_provider_rw()?;
1304
1305 for block in &database_blocks {
1307 provider_rw.insert_block(
1308 &block.clone().try_recover().expect("failed to seal block with senders"),
1309 )?;
1310 }
1311
1312 if let Some(first_block) = database_blocks.first() {
1314 provider_rw.write_state(
1315 &ExecutionOutcome {
1316 first_block: first_block.number,
1317 receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
1318 ..Default::default()
1319 },
1320 OriginalValuesKnown::No,
1321 StateWriteConfig::default(),
1322 )?;
1323 }
1324
1325 provider_rw.commit()?;
1326
1327 let provider = BlockchainProvider::new(factory)?;
1328
1329 let chain = NewCanonicalChain::Commit {
1331 new: in_memory_blocks
1332 .iter()
1333 .map(|block| {
1334 let senders = block.senders().expect("failed to recover senders");
1335 let block_receipts = receipts.get(block.number as usize).unwrap().clone();
1336 let execution_outcome = BlockExecutionOutput {
1337 result: BlockExecutionResult {
1338 receipts: block_receipts,
1339 requests: Default::default(),
1340 gas_used: 0,
1341 blob_gas_used: 0,
1342 },
1343 state: BundleState::default(),
1344 };
1345
1346 ExecutedBlock {
1347 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1348 block.clone(),
1349 senders,
1350 )),
1351 execution_output: execution_outcome.into(),
1352 ..Default::default()
1353 }
1354 })
1355 .collect(),
1356 };
1357 provider.canonical_in_memory_state.update_chain(chain);
1358 for state in provider.canonical_in_memory_state.canonical_chain() {
1359 provider.database.overlay_manager().insert_block(state.block());
1360 }
1361
1362 let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
1364 let block_count = blocks.len();
1365 let canonical_block = blocks.get(block_count - 1).unwrap();
1366 let safe_block = blocks.get(block_count - 2).unwrap();
1367 let finalized_block = blocks.get(block_count - 3).unwrap();
1368
1369 provider.set_canonical_head(canonical_block.clone_sealed_header());
1371 provider.set_safe(safe_block.clone_sealed_header());
1372 provider.set_finalized(finalized_block.clone_sealed_header());
1373
1374 Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
1375 }
1376
1377 #[expect(clippy::type_complexity)]
1378 fn provider_with_random_blocks(
1379 rng: &mut impl Rng,
1380 database_blocks: usize,
1381 in_memory_blocks: usize,
1382 block_range_params: BlockRangeParams,
1383 ) -> eyre::Result<(
1384 BlockchainProvider<MockNodeTypesWithDB>,
1385 Vec<SealedBlock<Block>>,
1386 Vec<SealedBlock<Block>>,
1387 Vec<Vec<Receipt>>,
1388 )> {
1389 provider_with_chain_spec_and_random_blocks(
1390 rng,
1391 MAINNET.clone(),
1392 database_blocks,
1393 in_memory_blocks,
1394 block_range_params,
1395 )
1396 }
1397
1398 fn persist_block_after_db_tx_creation(
1404 provider: BlockchainProvider<MockNodeTypesWithDB>,
1405 block_number: BlockNumber,
1406 ) {
1407 let hook_provider = provider.clone();
1408 provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
1409 if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
1410 state.anchor().number + 1 == block_number
1411 {
1412 let mut lowest_memory_block =
1413 state.parent_state_chain().last().expect("qed").block();
1414 let num_hash = lowest_memory_block.recovered_block().num_hash();
1415
1416 let execution_output = (*lowest_memory_block.execution_output).clone();
1417 lowest_memory_block.execution_output = Arc::new(execution_output);
1418
1419 let provider_rw = hook_provider.database_provider_rw().unwrap();
1421 let input = SaveBlocksInput::new(
1422 vec![lowest_memory_block],
1423 state.anchor().number,
1424 state.anchor().number,
1425 block_number,
1426 block_number,
1427 );
1428 provider_rw.save_blocks(&input).unwrap();
1429 provider_rw.commit().unwrap();
1430
1431 hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
1433 }
1434 }));
1435 }
1436
1437 #[test]
1438 fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1439 let mut rng = generators::rng();
1441 let factory = create_test_provider_factory();
1442
1443 let blocks = random_block_range(
1445 &mut rng,
1446 0..=10,
1447 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1448 );
1449 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1450
1451 let provider_rw = factory.provider_rw()?;
1453 for block in database_blocks {
1454 provider_rw.insert_block(
1455 &block.clone().try_recover().expect("failed to seal block with senders"),
1456 )?;
1457 }
1458
1459 provider_rw.commit()?;
1460
1461 let provider = BlockchainProvider::new(factory)?;
1463
1464 let first_db_block = database_blocks.first().unwrap();
1466 let first_in_mem_block = in_memory_blocks.first().unwrap();
1467 let last_in_mem_block = in_memory_blocks.last().unwrap();
1468
1469 assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1471 assert_eq!(
1472 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1473 None
1474 );
1475 assert_eq!(
1477 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1478 None
1479 );
1480
1481 let in_memory_block_senders =
1483 first_in_mem_block.senders().expect("failed to recover senders");
1484 let chain = NewCanonicalChain::Commit {
1485 new: vec![ExecutedBlock {
1486 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1487 first_in_mem_block.clone(),
1488 in_memory_block_senders,
1489 )),
1490 ..Default::default()
1491 }],
1492 };
1493 provider.canonical_in_memory_state.update_chain(chain);
1494
1495 assert_eq!(
1497 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1498 Some(first_in_mem_block.clone().into_block())
1499 );
1500 assert_eq!(
1501 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1502 Some(first_in_mem_block.clone().into_block())
1503 );
1504
1505 assert_eq!(
1507 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1508 Some(first_db_block.clone().into_block())
1509 );
1510 assert_eq!(
1511 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1512 Some(first_db_block.clone().into_block())
1513 );
1514
1515 assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1517
1518 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1520 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1521 last_in_mem_block.clone(),
1522 Default::default(),
1523 )),
1524 ..Default::default()
1525 });
1526
1527 assert_eq!(
1529 provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1530 Some(last_in_mem_block.clone().into_block())
1531 );
1532
1533 Ok(())
1534 }
1535
1536 #[test]
1537 fn test_block_reader_block() -> eyre::Result<()> {
1538 let mut rng = generators::rng();
1540 let factory = create_test_provider_factory();
1541
1542 let blocks = random_block_range(
1544 &mut rng,
1545 0..=10,
1546 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1547 );
1548 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1549
1550 let provider_rw = factory.provider_rw()?;
1552 for block in database_blocks {
1553 provider_rw.insert_block(
1554 &block.clone().try_recover().expect("failed to seal block with senders"),
1555 )?;
1556 }
1557 provider_rw.commit()?;
1558
1559 let provider = BlockchainProvider::new(factory)?;
1561
1562 let first_in_mem_block = in_memory_blocks.first().unwrap();
1564 let first_db_block = database_blocks.first().unwrap();
1566
1567 assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1569 assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1570
1571 let in_memory_block_senders =
1573 first_in_mem_block.senders().expect("failed to recover senders");
1574 let chain = NewCanonicalChain::Commit {
1575 new: vec![ExecutedBlock {
1576 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1577 first_in_mem_block.clone(),
1578 in_memory_block_senders,
1579 )),
1580 ..Default::default()
1581 }],
1582 };
1583 provider.canonical_in_memory_state.update_chain(chain);
1584
1585 assert_eq!(
1587 provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1588 Some(first_in_mem_block.clone().into_block())
1589 );
1590 assert_eq!(
1591 provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1592 Some(first_in_mem_block.clone().into_block())
1593 );
1594
1595 assert_eq!(
1597 provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1598 Some(first_db_block.clone().into_block())
1599 );
1600 assert_eq!(
1601 provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1602 Some(first_db_block.clone().into_block())
1603 );
1604
1605 Ok(())
1606 }
1607
1608 #[test]
1609 fn test_block_reader_pending_block() -> eyre::Result<()> {
1610 let mut rng = generators::rng();
1611 let (provider, _, _, _) = provider_with_random_blocks(
1612 &mut rng,
1613 TEST_BLOCKS_COUNT,
1614 TEST_BLOCKS_COUNT,
1615 BlockRangeParams::default(),
1616 )?;
1617
1618 let mut rng = generators::rng();
1620 let block = random_block(
1621 &mut rng,
1622 0,
1623 BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1624 );
1625
1626 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1628 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1629 block.clone(),
1630 block.senders().unwrap(),
1631 )),
1632 ..Default::default()
1633 });
1634
1635 assert_eq!(
1638 provider.pending_block()?,
1639 Some(RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()))
1640 );
1641
1642 assert_eq!(
1643 provider.pending_block_and_receipts()?,
1644 Some((RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()), vec![]))
1645 );
1646
1647 Ok(())
1648 }
1649
1650 #[test]
1651 fn test_block_body_indices() -> eyre::Result<()> {
1652 let mut rng = generators::rng();
1654 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1655 &mut rng,
1656 TEST_BLOCKS_COUNT,
1657 TEST_BLOCKS_COUNT,
1658 BlockRangeParams {
1659 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1660 ..Default::default()
1661 },
1662 )?;
1663
1664 let first_in_mem_block = in_memory_blocks.first().unwrap();
1665
1666 let in_memory_block_senders =
1668 first_in_mem_block.senders().expect("failed to recover senders");
1669 let chain = NewCanonicalChain::Commit {
1670 new: vec![ExecutedBlock {
1671 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1672 first_in_mem_block.clone(),
1673 in_memory_block_senders,
1674 )),
1675 ..Default::default()
1676 }],
1677 };
1678 provider.canonical_in_memory_state.update_chain(chain);
1679
1680 let first_db_block = database_blocks.first().unwrap().clone();
1681 let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1682
1683 assert_eq!(
1685 provider.block_body_indices(first_db_block.number)?.unwrap(),
1686 StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1687 );
1688
1689 assert_eq!(
1692 provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1693 StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1694 );
1695
1696 let mut rng = rand::rng();
1698 let random_block_number: u64 = rng.random();
1699 assert_eq!(provider.block_body_indices(random_block_number)?, None);
1700
1701 Ok(())
1702 }
1703
1704 #[test]
1705 fn test_block_hash_reader() -> eyre::Result<()> {
1706 let mut rng = generators::rng();
1707 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1708 &mut rng,
1709 TEST_BLOCKS_COUNT,
1710 TEST_BLOCKS_COUNT,
1711 BlockRangeParams::default(),
1712 )?;
1713
1714 let database_block = database_blocks.first().unwrap().clone();
1715 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1716
1717 assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1718 assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1719
1720 assert_eq!(
1721 provider.canonical_hashes_range(0, 10)?,
1722 [database_blocks, in_memory_blocks]
1723 .concat()
1724 .iter()
1725 .map(|block| block.hash())
1726 .collect::<Vec<_>>()
1727 );
1728
1729 Ok(())
1730 }
1731
1732 #[test]
1733 fn test_header_provider() -> eyre::Result<()> {
1734 let mut rng = generators::rng();
1735 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1736 &mut rng,
1737 TEST_BLOCKS_COUNT,
1738 TEST_BLOCKS_COUNT,
1739 BlockRangeParams::default(),
1740 )?;
1741
1742 let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1744 provider.set_finalized(finalized_block.clone_sealed_header());
1745
1746 let blocks = [database_blocks, in_memory_blocks].concat();
1747
1748 assert_eq!(
1749 provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1750 blocks
1751 .iter()
1752 .take_while(|header| header.number <= 8)
1753 .map(|b| b.clone_sealed_header())
1754 .collect::<Vec<_>>()
1755 );
1756
1757 Ok(())
1758 }
1759
1760 #[tokio::test]
1761 async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1762 let factory = create_test_provider_factory();
1763
1764 let mut test_block_builder = TestBlockBuilder::eth();
1766 let block_1 = test_block_builder.generate_random_block(0, B256::ZERO).try_recover()?;
1767 let block_hash_1 = block_1.hash();
1768
1769 let provider_rw = factory.provider_rw()?;
1771 provider_rw.insert_block(&block_1)?;
1772 provider_rw.commit()?;
1773
1774 let provider = BlockchainProvider::new(factory)?;
1775
1776 let in_memory_state = provider.canonical_in_memory_state();
1778 let mut rx_1 = provider.subscribe_to_canonical_state();
1779 let mut rx_2 = provider.subscribe_to_canonical_state();
1780
1781 let block_2 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1783 let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), BTreeMap::new());
1784 let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1785 in_memory_state.notify_canon_state(commit.clone());
1786 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1787 assert_eq!(notification_1, Ok(commit.clone()));
1788 assert_eq!(notification_2, Ok(commit.clone()));
1789
1790 let block_3 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1792 let block_4 = test_block_builder.generate_random_block(2, block_3.hash()).try_recover()?;
1793 let new_chain =
1794 Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), BTreeMap::new());
1795 let re_org =
1796 CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1797 in_memory_state.notify_canon_state(re_org.clone());
1798 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1799 assert_eq!(notification_1, Ok(re_org.clone()));
1800 assert_eq!(notification_2, Ok(re_org.clone()));
1801
1802 Ok(())
1803 }
1804
1805 #[test]
1806 fn test_block_num_reader() -> eyre::Result<()> {
1807 let mut rng = generators::rng();
1808 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1809 &mut rng,
1810 TEST_BLOCKS_COUNT,
1811 TEST_BLOCKS_COUNT,
1812 BlockRangeParams::default(),
1813 )?;
1814
1815 assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1816 assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1817
1818 let database_block = database_blocks.first().unwrap().clone();
1819 let in_memory_block = in_memory_blocks.first().unwrap().clone();
1820 assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1821 assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1822
1823 Ok(())
1824 }
1825
1826 #[test]
1827 fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1828 let mut rng = generators::rng();
1829 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1830 &mut rng,
1831 TEST_BLOCKS_COUNT,
1832 TEST_BLOCKS_COUNT,
1833 BlockRangeParams::default(),
1834 )?;
1835
1836 let database_block = database_blocks.first().unwrap().clone();
1837 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1838
1839 let block_number = database_block.number;
1840 let block_hash = database_block.hash();
1841
1842 assert_eq!(
1843 provider.block_by_id(block_number.into()).unwrap(),
1844 Some(database_block.clone().into_block())
1845 );
1846 assert_eq!(
1847 provider.block_by_id(block_hash.into()).unwrap(),
1848 Some(database_block.into_block())
1849 );
1850
1851 let block_number = in_memory_block.number;
1852 let block_hash = in_memory_block.hash();
1853 assert_eq!(
1854 provider.block_by_id(block_number.into()).unwrap(),
1855 Some(in_memory_block.clone().into_block())
1856 );
1857 assert_eq!(
1858 provider.block_by_id(block_hash.into()).unwrap(),
1859 Some(in_memory_block.into_block())
1860 );
1861
1862 Ok(())
1863 }
1864
1865 #[test]
1866 fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1867 let mut rng = generators::rng();
1868 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1869 &mut rng,
1870 TEST_BLOCKS_COUNT,
1871 TEST_BLOCKS_COUNT,
1872 BlockRangeParams::default(),
1873 )?;
1874
1875 let database_block = database_blocks.first().unwrap().clone();
1876
1877 let in_memory_block_count = in_memory_blocks.len();
1878 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1879 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1880 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1881
1882 let block_number = database_block.number;
1883 assert_eq!(
1884 provider.header_by_number_or_tag(block_number.into()).unwrap(),
1885 Some(database_block.header().clone())
1886 );
1887 assert_eq!(
1888 provider.sealed_header_by_number_or_tag(block_number.into())?,
1889 Some(database_block.clone_sealed_header())
1890 );
1891
1892 assert_eq!(
1893 provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1894 Some(canonical_block.header().clone())
1895 );
1896 assert_eq!(
1897 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1898 Some(canonical_block.clone_sealed_header())
1899 );
1900
1901 assert_eq!(
1902 provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1903 Some(safe_block.header().clone())
1904 );
1905 assert_eq!(
1906 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1907 Some(safe_block.clone_sealed_header())
1908 );
1909
1910 assert_eq!(
1911 provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1912 Some(finalized_block.header().clone())
1913 );
1914 assert_eq!(
1915 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1916 Some(finalized_block.clone_sealed_header())
1917 );
1918
1919 Ok(())
1920 }
1921
1922 #[test]
1923 fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1924 let mut rng = generators::rng();
1925 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1926 &mut rng,
1927 TEST_BLOCKS_COUNT,
1928 TEST_BLOCKS_COUNT,
1929 BlockRangeParams::default(),
1930 )?;
1931
1932 let database_block = database_blocks.first().unwrap().clone();
1933 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1934
1935 let block_number = database_block.number;
1936 let block_hash = database_block.hash();
1937
1938 assert_eq!(
1939 provider.header_by_id(block_number.into()).unwrap(),
1940 Some(database_block.header().clone())
1941 );
1942 assert_eq!(
1943 provider.sealed_header_by_id(block_number.into()).unwrap(),
1944 Some(database_block.clone_sealed_header())
1945 );
1946
1947 assert_eq!(
1948 provider.header_by_id(block_hash.into()).unwrap(),
1949 Some(database_block.header().clone())
1950 );
1951 assert_eq!(
1952 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1953 Some(database_block.clone_sealed_header())
1954 );
1955
1956 let block_number = in_memory_block.number;
1957 let block_hash = in_memory_block.hash();
1958
1959 assert_eq!(
1960 provider.header_by_id(block_number.into()).unwrap(),
1961 Some(in_memory_block.header().clone())
1962 );
1963 assert_eq!(
1964 provider.sealed_header_by_id(block_number.into()).unwrap(),
1965 Some(in_memory_block.clone_sealed_header())
1966 );
1967
1968 assert_eq!(
1969 provider.header_by_id(block_hash.into()).unwrap(),
1970 Some(in_memory_block.header().clone())
1971 );
1972 assert_eq!(
1973 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1974 Some(in_memory_block.clone_sealed_header())
1975 );
1976
1977 Ok(())
1978 }
1979
1980 #[test]
1981 fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
1982 let mut rng = generators::rng();
1983 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1984 &mut rng,
1985 TEST_BLOCKS_COUNT,
1986 TEST_BLOCKS_COUNT,
1987 BlockRangeParams { tx_count: 1..3, ..Default::default() },
1988 )?;
1989
1990 let database_block = database_blocks.first().unwrap().clone();
1991 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1992
1993 let block_number = database_block.number;
1994 let block_hash = database_block.hash();
1995
1996 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1997 assert!(!provider
1998 .receipts_by_number_or_tag(database_block.number.into())?
1999 .unwrap()
2000 .is_empty());
2001
2002 assert_eq!(
2003 provider.receipts_by_block_id(block_number.into())?.unwrap(),
2004 receipts.get(block_number as usize).unwrap().clone()
2005 );
2006 assert_eq!(
2007 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
2008 receipts.get(block_number as usize).unwrap().clone()
2009 );
2010
2011 let block_number = in_memory_block.number;
2012 let block_hash = in_memory_block.hash();
2013
2014 assert_eq!(
2015 provider.receipts_by_block_id(block_number.into())?.unwrap(),
2016 receipts.get(block_number as usize).unwrap().clone()
2017 );
2018 assert_eq!(
2019 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
2020 receipts.get(block_number as usize).unwrap().clone()
2021 );
2022
2023 Ok(())
2024 }
2025
2026 #[test]
2027 fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
2028 let mut rng = generators::rng();
2029 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2030 &mut rng,
2031 TEST_BLOCKS_COUNT,
2032 TEST_BLOCKS_COUNT,
2033 BlockRangeParams { tx_count: 1..3, ..Default::default() },
2034 )?;
2035
2036 let database_block = database_blocks.first().unwrap().clone();
2037
2038 let in_memory_block_count = in_memory_blocks.len();
2039 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
2040 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
2041 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
2042
2043 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
2044 assert!(!provider
2045 .receipts_by_number_or_tag(database_block.number.into())?
2046 .unwrap()
2047 .is_empty());
2048
2049 assert_eq!(
2050 provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
2051 receipts.get(database_block.number as usize).unwrap().clone()
2052 );
2053 assert_eq!(
2054 provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
2055 receipts.get(canonical_block.number as usize).unwrap().clone()
2056 );
2057 assert_eq!(
2058 provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
2059 receipts.get(safe_block.number as usize).unwrap().clone()
2060 );
2061 assert_eq!(
2062 provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
2063 receipts.get(finalized_block.number as usize).unwrap().clone()
2064 );
2065
2066 Ok(())
2067 }
2068
2069 #[test]
2070 fn test_changeset_reader() -> eyre::Result<()> {
2071 let mut rng = generators::rng();
2072
2073 let (database_blocks, in_memory_blocks) =
2074 random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
2075
2076 let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
2077 let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
2078 let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
2079
2080 let accounts = random_eoa_accounts(&mut rng, 2);
2081
2082 let (database_changesets, database_state) = random_changeset_range(
2083 &mut rng,
2084 &database_blocks,
2085 accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
2086 0..0,
2087 0..0,
2088 );
2089 let (in_memory_changesets, in_memory_state) = random_changeset_range(
2090 &mut rng,
2091 &in_memory_blocks,
2092 database_state
2093 .iter()
2094 .map(|(address, (account, storage))| (*address, (*account, storage.clone()))),
2095 0..0,
2096 0..0,
2097 );
2098
2099 let factory = create_test_provider_factory();
2100
2101 let provider_rw = factory.provider_rw()?;
2102 provider_rw.append_blocks_with_state(
2103 database_blocks
2104 .into_iter()
2105 .map(|b| b.try_recover().expect("failed to seal block with senders"))
2106 .collect(),
2107 &ExecutionOutcome {
2108 bundle: BundleState::new(
2109 database_state.into_iter().map(|(address, (account, _))| {
2110 (address, None, Some(account.into()), Default::default())
2111 }),
2112 database_changesets.iter().map(|block_changesets| {
2113 block_changesets.iter().map(|(address, account, _)| {
2114 (*address, Some(Some((*account).into())), [])
2115 })
2116 }),
2117 Vec::new(),
2118 ),
2119 first_block: first_database_block,
2120 ..Default::default()
2121 },
2122 Default::default(),
2123 )?;
2124 provider_rw.commit()?;
2125
2126 let provider = BlockchainProvider::new(factory)?;
2127
2128 let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
2129 let chain = NewCanonicalChain::Commit {
2130 new: vec![in_memory_blocks
2131 .first()
2132 .map(|block| {
2133 let senders = block.senders().expect("failed to recover senders");
2134 ExecutedBlock {
2135 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2136 block.clone(),
2137 senders,
2138 )),
2139 execution_output: Arc::new(BlockExecutionOutput {
2140 state: BundleState::new(
2141 in_memory_state.into_iter().map(|(address, (account, _))| {
2142 (address, None, Some(account.into()), Default::default())
2143 }),
2144 [in_memory_changesets.iter().map(|(address, account, _)| {
2145 (*address, Some(Some((*account).into())), Vec::new())
2146 })],
2147 [],
2148 ),
2149 result: BlockExecutionResult {
2150 receipts: Default::default(),
2151 requests: Default::default(),
2152 gas_used: 0,
2153 blob_gas_used: 0,
2154 },
2155 }),
2156 ..Default::default()
2157 }
2158 })
2159 .unwrap()],
2160 };
2161 provider.canonical_in_memory_state.update_chain(chain);
2162
2163 assert_eq!(
2164 provider.account_block_changeset(last_database_block).unwrap(),
2165 database_changesets
2166 .into_iter()
2167 .next_back()
2168 .unwrap()
2169 .into_iter()
2170 .sorted_by_key(|(address, _, _)| *address)
2171 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2172 .collect::<Vec<_>>()
2173 );
2174 assert_eq!(
2175 provider.account_block_changeset(first_in_memory_block).unwrap(),
2176 in_memory_changesets
2177 .into_iter()
2178 .sorted_by_key(|(address, _, _)| *address)
2179 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2180 .collect::<Vec<_>>()
2181 );
2182
2183 Ok(())
2184 }
2185
2186 #[test]
2187 fn test_state_provider_factory() -> eyre::Result<()> {
2188 let mut rng = generators::rng();
2189
2190 let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2192 &mut rng,
2193 TEST_BLOCKS_COUNT,
2194 TEST_BLOCKS_COUNT,
2195 BlockRangeParams::default(),
2196 )?;
2197
2198 let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
2200 &mut rng,
2201 TEST_BLOCKS_COUNT,
2202 0,
2203 BlockRangeParams::default(),
2204 )?;
2205
2206 let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
2207 let first_in_memory_block = in_memory_blocks.first().unwrap();
2208 let first_db_block = database_blocks.first().unwrap();
2209
2210 assert_eq!(
2212 first_in_memory_block.hash(),
2213 in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
2214 );
2215 assert_eq!(
2217 first_db_block.hash(),
2218 only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
2219 );
2220
2221 assert_eq!(
2223 first_in_memory_block.hash(),
2224 in_memory_provider
2225 .history_by_block_number(first_in_memory_block.number)?
2226 .block_hash(first_in_memory_block.number)?
2227 .unwrap()
2228 );
2229 assert_eq!(
2230 first_db_block.hash(),
2231 only_database_provider
2232 .history_by_block_number(first_db_block.number)?
2233 .block_hash(first_db_block.number)?
2234 .unwrap()
2235 );
2236 assert_eq!(
2237 first_in_memory_block.hash(),
2238 in_memory_provider
2239 .history_by_block_hash(first_in_memory_block.hash())?
2240 .block_hash(first_in_memory_block.number)?
2241 .unwrap()
2242 );
2243 assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
2244
2245 assert_eq!(
2247 first_in_memory_block.hash(),
2248 in_memory_provider
2249 .state_by_block_hash(first_in_memory_block.hash())?
2250 .block_hash(first_in_memory_block.number)?
2251 .unwrap()
2252 );
2253 assert_eq!(
2254 first_db_block.hash(),
2255 only_database_provider
2256 .state_by_block_hash(first_db_block.hash())?
2257 .block_hash(first_db_block.number)?
2258 .unwrap()
2259 );
2260 assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
2261
2262 assert_eq!(
2264 first_in_memory_block.hash(),
2265 in_memory_provider
2266 .pending()
2267 .unwrap()
2268 .block_hash(first_in_memory_block.number)
2269 .unwrap()
2270 .unwrap()
2271 );
2272
2273 let pending_block = database_blocks[database_blocks.len() - 1].clone();
2275 only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2276 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2277 pending_block.clone(),
2278 Default::default(),
2279 )),
2280 ..Default::default()
2281 });
2282
2283 assert_eq!(
2284 pending_block.hash(),
2285 only_database_provider
2286 .pending()
2287 .unwrap()
2288 .block_hash(pending_block.number)
2289 .unwrap()
2290 .unwrap()
2291 );
2292
2293 assert_eq!(
2294 pending_block.hash(),
2295 only_database_provider
2296 .pending_state_by_hash(pending_block.hash())?
2297 .unwrap()
2298 .block_hash(pending_block.number)?
2299 .unwrap()
2300 );
2301
2302 assert_eq!(
2304 first_in_memory_block.hash(),
2305 in_memory_provider
2306 .state_by_block_number_or_tag(BlockNumberOrTag::Number(
2307 first_in_memory_block.number
2308 ))?
2309 .block_hash(first_in_memory_block.number)?
2310 .unwrap()
2311 );
2312 assert_eq!(
2313 first_in_memory_block.hash(),
2314 in_memory_provider
2315 .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
2316 .block_hash(first_in_memory_block.number)?
2317 .unwrap()
2318 );
2319 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2321 in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2322 assert_eq!(
2323 safe_block.hash(),
2324 in_memory_provider
2325 .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
2326 .block_hash(safe_block.number)?
2327 .unwrap()
2328 );
2329 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2331 in_memory_provider
2332 .canonical_in_memory_state
2333 .set_finalized(finalized_block.clone_sealed_header());
2334 assert_eq!(
2335 finalized_block.hash(),
2336 in_memory_provider
2337 .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
2338 .block_hash(finalized_block.number)?
2339 .unwrap()
2340 );
2341 let earliest_block = blocks.first().unwrap().clone();
2343 assert_eq!(
2344 earliest_block.hash(),
2345 only_database_provider
2346 .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
2347 .block_hash(earliest_block.number)?
2348 .unwrap()
2349 );
2350
2351 Ok(())
2352 }
2353
2354 #[test]
2355 fn test_block_id_reader() -> eyre::Result<()> {
2356 let mut rng = generators::rng();
2358 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2359 &mut rng,
2360 TEST_BLOCKS_COUNT,
2361 TEST_BLOCKS_COUNT,
2362 BlockRangeParams::default(),
2363 )?;
2364
2365 let pending_block = in_memory_blocks.last().unwrap();
2367 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2368 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2369 pending_block.clone(),
2370 Default::default(),
2371 )),
2372 ..Default::default()
2373 });
2374
2375 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2377 provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2378
2379 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2381 provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
2382
2383 assert_eq!(
2385 provider.pending_block_num_hash()?,
2386 Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
2387 );
2388
2389 assert_eq!(
2391 provider.safe_block_num_hash()?,
2392 Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
2393 );
2394
2395 assert_eq!(
2397 provider.finalized_block_num_hash()?,
2398 Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
2399 );
2400
2401 Ok(())
2402 }
2403
2404 macro_rules! test_by_tx_range {
2405 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2406
2407 let extra_blocks = [$(stringify!($method)),*].len();
2410
2411 let mut rng = generators::rng();
2412 let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
2413 &mut rng,
2414 TEST_BLOCKS_COUNT,
2415 TEST_BLOCKS_COUNT + extra_blocks,
2416 BlockRangeParams {
2417 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2418 ..Default::default()
2419 },
2420 )?;
2421
2422 $(
2423 let db_tx_count =
2425 database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2426 let in_mem_tx_count =
2427 in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2428
2429 let db_range = 0..=(db_tx_count - 1);
2430 let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
2431
2432 let database_data =
2434 database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2435 assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
2436
2437 let in_memory_data =
2439 in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2440 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
2441
2442 assert_eq!(
2444 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2445 &in_memory_data[1..in_memory_data.len() - 1],
2446 "partial mem data"
2447 );
2448
2449 assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
2451
2452 assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
2454
2455 assert_eq!(
2457 provider.$method(in_mem_range.start() - 2..)?,
2458 database_data[database_data.len() - 2..]
2459 .iter()
2460 .chain(&in_memory_data[..])
2461 .cloned()
2462 .collect::<Vec<_>>(),
2463 "unbounded span data"
2464 );
2465
2466 {
2468 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2470
2471 assert_eq!(
2472 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2473 database_data[database_data.len() - 2..]
2474 .iter()
2475 .chain(&in_memory_data[..in_memory_data.len() - 1])
2476 .cloned()
2477 .collect::<Vec<_>>(),
2478 "span data"
2479 );
2480
2481 database_blocks.push(in_memory_blocks.remove(0));
2483 }
2484
2485 let start_tx_num = u64::MAX;
2487 let end_tx_num = u64::MAX;
2488 let result = provider.$method(start_tx_num..end_tx_num)?;
2489 assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2490
2491 let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2493 assert!(result.is_empty(), "No data should be found for an empty transaction range");
2494 )*
2495 }};
2496 }
2497
2498 #[test]
2499 fn test_methods_by_tx_range() -> eyre::Result<()> {
2500 test_by_tx_range!([
2501 (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2502 .senders()
2503 .unwrap()),
2504 (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2505 .body()
2506 .transactions
2507 .clone()),
2508 (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2509 receipts[block.number as usize].clone()
2510 })
2511 ]);
2512
2513 Ok(())
2514 }
2515
2516 macro_rules! test_by_block_range {
2517 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2518 let extra_blocks = [$(stringify!($method)),*].len();
2521
2522 let mut rng = generators::rng();
2523 let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2524 &mut rng,
2525 TEST_BLOCKS_COUNT,
2526 TEST_BLOCKS_COUNT + extra_blocks,
2527 BlockRangeParams {
2528 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2529 ..Default::default()
2530 },
2531 )?;
2532
2533 $(
2534 let db_block_count = database_blocks.len() as u64;
2536 let in_mem_block_count = in_memory_blocks.len() as u64;
2537
2538 let db_range = 0..=db_block_count - 1;
2539 let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2540
2541 let database_data =
2543 database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2544 assert_eq!(provider.$method(db_range.clone())?, database_data);
2545
2546 let in_memory_data =
2548 in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2549 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2550
2551 assert_eq!(
2553 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2554 &in_memory_data[1..in_memory_data.len() - 1]
2555 );
2556
2557 {
2559
2560 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2562
2563 assert_eq!(
2564 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2565 database_data[database_data.len() - 2..]
2566 .iter()
2567 .chain(&in_memory_data[..in_memory_data.len() - 1])
2568 .cloned()
2569 .collect::<Vec<_>>()
2570 );
2571
2572 database_blocks.push(in_memory_blocks.remove(0));
2574 }
2575
2576 let start_block_num = u64::MAX;
2578 let end_block_num = u64::MAX;
2579 let result = provider.$method(start_block_num..=end_block_num-1)?;
2580 assert!(result.is_empty(), "No data should be found for an invalid block range");
2581
2582 let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2584 assert!(result.is_empty(), "No data should be found for an empty block range");
2585 )*
2586 }};
2587 }
2588
2589 #[test]
2590 fn test_methods_by_block_range() -> eyre::Result<()> {
2591 test_by_block_range!([
2594 (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2595 (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2596 (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2597 (block_with_senders_range, |block: &SealedBlock<Block>| block
2598 .clone()
2599 .try_recover()
2600 .unwrap()),
2601 (recovered_block_range, |block: &SealedBlock<Block>| block
2602 .clone()
2603 .try_recover()
2604 .unwrap()),
2605 (transactions_by_block_range, |block: &SealedBlock<Block>| block
2606 .body()
2607 .transactions
2608 .clone()),
2609 ]);
2610
2611 Ok(())
2612 }
2613
2614 macro_rules! call_method {
2616 ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2617 let result = $provider.$method($($args),*)?;
2618 assert_eq!(
2619 result,
2620 $expected_item,
2621 "{}: item does not match the expected item for arguments {:?}",
2622 stringify!($method),
2623 ($($args),*)
2624 );
2625 }};
2626
2627 (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2629 let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2630 call_method!($provider, $method, (arg), expected_item);
2631 }};
2632
2633 (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2635 let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2636 call_method!($provider, $method, (arg1, arg2), expected_item);
2637 }};
2638 }
2639
2640 macro_rules! test_non_range {
2645 ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2646
2647 let extra_blocks = [$(stringify!($arg_count)),*].len();
2650
2651 let mut rng = generators::rng();
2652 let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2653 &mut rng,
2654 TEST_BLOCKS_COUNT,
2655 TEST_BLOCKS_COUNT + extra_blocks,
2656 BlockRangeParams {
2657 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2658 ..Default::default()
2659 },
2660 )?;
2661
2662 let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2663
2664 $(
2665 let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2666 let tx_num = |block: &SealedBlock<Block>| {
2667 database_blocks
2668 .iter()
2669 .chain(in_memory_blocks.iter())
2670 .take_while(|b| b.number < block.number)
2671 .map(|b| b.transaction_count())
2672 .sum::<usize>() as u64
2673 };
2674
2675 {
2677 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2679
2680 call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2681
2682 database_blocks.push(in_memory_blocks.pop_front().unwrap());
2684 }
2685
2686 let tx_num = |block: &SealedBlock<Block>| {
2688 database_blocks
2689 .iter()
2690 .chain(in_memory_blocks.iter())
2691 .take_while(|b| b.number < block.number)
2692 .map(|b| b.transaction_count())
2693 .sum::<usize>() as u64
2694 };
2695
2696 {
2698 call_method!($arg_count, provider, $method, |_,_,_,_| ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2699 }
2700
2701 {
2703 let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2704
2705 let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2706 call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2707
2708 call_method!($arg_count, provider.database, $method, |_,_,_,_| (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2710 }
2711 )*
2712 }};
2713}
2714
2715 #[test]
2716 fn test_non_range_methods() -> eyre::Result<()> {
2717 let test_tx_index = 0;
2718
2719 test_non_range!([
2720 (
2721 ONE,
2722 header,
2723 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2724 block.hash(),
2725 Some(block.header().clone())
2726 ),
2727 B256::random()
2728 ),
2729 (
2730 ONE,
2731 header_by_number,
2732 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2733 block.number,
2734 Some(block.header().clone())
2735 ),
2736 u64::MAX
2737 ),
2738 (
2739 ONE,
2740 sealed_header,
2741 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2742 block.number,
2743 Some(block.clone_sealed_header())
2744 ),
2745 u64::MAX
2746 ),
2747 (
2748 ONE,
2749 block_hash,
2750 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2751 block.number,
2752 Some(block.hash())
2753 ),
2754 u64::MAX
2755 ),
2756 (
2757 ONE,
2758 block_number,
2759 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2760 block.hash(),
2761 Some(block.number)
2762 ),
2763 B256::random()
2764 ),
2765 (
2766 ONE,
2767 block,
2768 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2769 BlockHashOrNumber::Hash(block.hash()),
2770 Some(block.clone().into_block())
2771 ),
2772 BlockHashOrNumber::Hash(B256::random())
2773 ),
2774 (
2775 ONE,
2776 block,
2777 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2778 BlockHashOrNumber::Number(block.number),
2779 Some(block.clone().into_block())
2780 ),
2781 BlockHashOrNumber::Number(u64::MAX)
2782 ),
2783 (
2784 ONE,
2785 block_body_indices,
2786 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2787 block.number,
2788 Some(StoredBlockBodyIndices {
2789 first_tx_num: tx_num,
2790 tx_count: block.transaction_count() as u64
2791 })
2792 ),
2793 u64::MAX
2794 ),
2795 (
2796 TWO,
2797 recovered_block,
2798 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2799 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2800 block.clone().try_recover().ok()
2801 ),
2802 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2803 ),
2804 (
2805 TWO,
2806 recovered_block,
2807 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2808 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2809 block.clone().try_recover().ok()
2810 ),
2811 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2812 ),
2813 (
2814 TWO,
2815 sealed_block_with_senders,
2816 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2817 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2818 block.clone().try_recover().ok()
2819 ),
2820 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2821 ),
2822 (
2823 TWO,
2824 sealed_block_with_senders,
2825 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2826 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2827 block.clone().try_recover().ok()
2828 ),
2829 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2830 ),
2831 (
2832 ONE,
2833 transaction_id,
2834 |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2835 tx_hash,
2836 Some(tx_num)
2837 ),
2838 B256::random()
2839 ),
2840 (
2841 ONE,
2842 transaction_by_id,
2843 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2844 tx_num,
2845 Some(block.body().transactions[test_tx_index].clone())
2846 ),
2847 u64::MAX
2848 ),
2849 (
2850 ONE,
2851 transaction_by_id_unhashed,
2852 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2853 tx_num,
2854 Some(block.body().transactions[test_tx_index].clone())
2855 ),
2856 u64::MAX
2857 ),
2858 (
2859 ONE,
2860 transaction_by_hash,
2861 |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2862 tx_hash,
2863 Some(block.body().transactions[test_tx_index].clone())
2864 ),
2865 B256::random()
2866 ),
2867 (
2868 ONE,
2869 block_by_transaction_id,
2870 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2871 tx_num,
2872 Some(block.number)
2873 ),
2874 u64::MAX
2875 ),
2876 (
2877 ONE,
2878 transactions_by_block,
2879 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2880 BlockHashOrNumber::Number(block.number),
2881 Some(block.body().transactions.clone())
2882 ),
2883 BlockHashOrNumber::Number(u64::MAX)
2884 ),
2885 (
2886 ONE,
2887 transactions_by_block,
2888 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2889 BlockHashOrNumber::Hash(block.hash()),
2890 Some(block.body().transactions.clone())
2891 ),
2892 BlockHashOrNumber::Number(u64::MAX)
2893 ),
2894 (
2895 ONE,
2896 transaction_sender,
2897 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2898 tx_num,
2899 block.body().transactions[test_tx_index].recover_signer().ok()
2900 ),
2901 u64::MAX
2902 ),
2903 (
2904 ONE,
2905 receipt,
2906 |block: &SealedBlock<Block>,
2907 tx_num: TxNumber,
2908 _: B256,
2909 receipts: &Vec<Vec<Receipt>>| (
2910 tx_num,
2911 Some(receipts[block.number as usize][test_tx_index].clone())
2912 ),
2913 u64::MAX
2914 ),
2915 (
2916 ONE,
2917 receipt_by_hash,
2918 |block: &SealedBlock<Block>,
2919 _: TxNumber,
2920 tx_hash: B256,
2921 receipts: &Vec<Vec<Receipt>>| (
2922 tx_hash,
2923 Some(receipts[block.number as usize][test_tx_index].clone())
2924 ),
2925 B256::random()
2926 ),
2927 (
2928 ONE,
2929 receipts_by_block,
2930 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2931 BlockHashOrNumber::Number(block.number),
2932 Some(receipts[block.number as usize].clone())
2933 ),
2934 BlockHashOrNumber::Number(u64::MAX)
2935 ),
2936 (
2937 ONE,
2938 receipts_by_block,
2939 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2940 BlockHashOrNumber::Hash(block.hash()),
2941 Some(receipts[block.number as usize].clone())
2942 ),
2943 BlockHashOrNumber::Hash(B256::random())
2944 ),
2945 ]);
2947
2948 Ok(())
2949 }
2950
2951 #[test]
2952 fn test_race() -> eyre::Result<()> {
2953 let mut rng = generators::rng();
2954 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2955 &mut rng,
2956 TEST_BLOCKS_COUNT - 1,
2957 TEST_BLOCKS_COUNT + 1,
2958 BlockRangeParams {
2959 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2960 ..Default::default()
2961 },
2962 )?;
2963
2964 let old_transaction_hash_fn =
2967 |hash: B256,
2968 canonical_in_memory_state: CanonicalInMemoryState,
2969 factory: ProviderFactory<MockNodeTypesWithDB>| {
2970 assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2971 Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2972 };
2973
2974 let correct_transaction_hash_fn =
2976 |hash: B256,
2977 canonical_in_memory_state: CanonicalInMemoryState,
2978 _factory: ProviderFactory<MockNodeTypesWithDB>| {
2979 if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
2980 return Ok::<_, ProviderError>(Some(tx));
2981 }
2982 panic!("should not be in database");
2983 };
2985
2986 {
2988 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2991 let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
2992
2993 assert!(matches!(
2996 old_transaction_hash_fn(
2997 *to_be_persisted_tx.tx_hash(),
2998 provider.canonical_in_memory_state(),
2999 provider.database.clone()
3000 ),
3001 Ok(None)
3002 ));
3003 }
3004
3005 {
3007 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
3010 let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
3011
3012 assert_eq!(
3013 correct_transaction_hash_fn(
3014 *to_be_persisted_tx.tx_hash(),
3015 provider.canonical_in_memory_state(),
3016 provider.database
3017 )
3018 .unwrap(),
3019 Some(to_be_persisted_tx)
3020 );
3021 }
3022
3023 Ok(())
3024 }
3025
3026 fn random_account(nonce: u64) -> (Address, Account) {
3027 (Address::random(), Account { nonce, balance: U256::from(nonce), bytecode_hash: None })
3028 }
3029
3030 fn test_provider_factory_with_genesis() -> eyre::Result<ProviderFactory<MockNodeTypesWithDB>> {
3032 let factory = create_test_provider_factory();
3033 let provider_rw = factory.provider_rw()?;
3034 let mut rng = generators::rng();
3035 let genesis =
3036 random_block(&mut rng, 0, BlockParams { tx_count: Some(0), ..Default::default() });
3037 provider_rw
3038 .insert_block(&genesis.try_recover().expect("failed to seal block with senders"))?;
3039 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(0))?;
3040 provider_rw.commit()?;
3041 Ok(factory)
3042 }
3043
3044 #[test]
3045 fn state_range_provider_account_range_is_sorted_and_bounded() -> eyre::Result<()> {
3046 let factory = test_provider_factory_with_genesis()?;
3047 let provider_rw = factory.provider_rw()?;
3048
3049 let accounts: Vec<_> = (0..5u64).map(random_account).collect();
3050 provider_rw.insert_account_for_hashing(
3051 accounts.iter().map(|(address, account)| (*address, Some(*account))),
3052 )?;
3053 provider_rw.commit()?;
3054
3055 let provider = BlockchainProvider::new(factory)?;
3056
3057 let mut expected: Vec<_> =
3058 accounts.iter().map(|(address, account)| (keccak256(address), *account)).collect();
3059 expected.sort_by_key(|(hash, _)| *hash);
3060 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3061
3062 let all = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3063 assert_eq!(all.end, RangeEnd::Exhausted);
3064 assert_eq!(all.items, expected);
3065
3066 let bounded = state.account_range(B256::ZERO, expected[1].0, 10_000)?;
3069 assert_eq!(bounded.end, RangeEnd::HashLimit);
3070 assert_eq!(bounded.items, expected[..2]);
3071
3072 Ok(())
3073 }
3074
3075 #[test]
3076 fn state_range_provider_account_range_respects_response_bytes() -> eyre::Result<()> {
3077 let factory = test_provider_factory_with_genesis()?;
3078 let provider_rw = factory.provider_rw()?;
3079
3080 let accounts: Vec<_> = (0..5u64).map(random_account).collect();
3081 provider_rw.insert_account_for_hashing(
3082 accounts.iter().map(|(address, account)| (*address, Some(*account))),
3083 )?;
3084 provider_rw.commit()?;
3085
3086 let provider = BlockchainProvider::new(factory)?;
3087 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3088
3089 let partial = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 150)?;
3091 assert_eq!(partial.end, RangeEnd::ByteLimit);
3092 assert_eq!(partial.items.len(), 1);
3093
3094 Ok(())
3095 }
3096
3097 #[test]
3098 fn state_range_provider_storage_range_and_root() -> eyre::Result<()> {
3099 let factory = test_provider_factory_with_genesis()?;
3100 let provider_rw = factory.provider_rw()?;
3101
3102 let (address, account) = random_account(1);
3103 let hashed_address = keccak256(address);
3104 provider_rw.insert_account_for_hashing([(address, Some(account))])?;
3105 let slots = [
3106 StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) },
3107 StorageEntry { key: B256::with_last_byte(2), value: U256::from(20) },
3108 ];
3109 provider_rw.insert_storage_for_hashing([(address, slots)])?;
3110 provider_rw.commit()?;
3111
3112 let provider = BlockchainProvider::new(factory)?;
3113 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3114
3115 let expected_root = provider.latest()?.storage_root(address, HashedStorage::default())?;
3116 assert_eq!(state.storage_root_by_hash(hashed_address)?, expected_root);
3117
3118 let returned = state
3119 .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3120 .unwrap();
3121 assert_eq!(returned.end, RangeEnd::Exhausted);
3122 let mut expected: Vec<_> =
3123 slots.iter().map(|entry| (keccak256(entry.key), entry.value)).collect();
3124 expected.sort_by_key(|(hash, _)| *hash);
3125 assert_eq!(returned.items, expected);
3126
3127 let empty_window =
3129 state.storage_range(hashed_address, B256::ZERO, B256::ZERO, 10_000)?.unwrap();
3130 assert_eq!(empty_window.end, RangeEnd::HashLimit);
3131 assert_eq!(empty_window.items, expected[..1]);
3132
3133 assert!(state
3135 .storage_range(B256::repeat_byte(0xee), B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3136 .is_none());
3137
3138 Ok(())
3139 }
3140
3141 #[test]
3142 fn state_range_provider_proofs_start_at_the_real_root() -> eyre::Result<()> {
3143 let factory = test_provider_factory_with_genesis()?;
3144 let provider_rw = factory.provider_rw()?;
3145
3146 let (address, account) = random_account(1);
3147 let hashed_address = keccak256(address);
3148 let hashed_slot = keccak256(B256::with_last_byte(1));
3149 provider_rw.insert_account_for_hashing([(address, Some(account))])?;
3150 provider_rw.insert_storage_for_hashing([(
3151 address,
3152 [StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) }],
3153 )])?;
3154 provider_rw.commit()?;
3155
3156 let provider = BlockchainProvider::new(factory)?;
3157
3158 let state_root = provider.latest()?.state_root(HashedPostState::default())?;
3161 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3162 let account_proof = state.account_range_proof(&[hashed_address])?;
3163 assert!(!account_proof.is_empty());
3164 assert_eq!(keccak256(&account_proof[0]), state_root);
3165
3166 let storage_root = state.storage_root_by_hash(hashed_address)?;
3167 let storage_proof = state.storage_range_proof(hashed_address, &[hashed_slot])?;
3168 assert!(!storage_proof.is_empty());
3169 assert_eq!(keccak256(&storage_proof[0]), storage_root);
3170
3171 Ok(())
3172 }
3173
3174 #[test]
3175 fn state_range_provider_serves_recent_root_and_rejects_expired_root() -> eyre::Result<()> {
3176 let mut rng = generators::rng();
3177 let factory = create_test_provider_factory();
3178 let provider_rw = factory.provider_rw()?;
3179 let expired_root = B256::repeat_byte(0x11);
3180 let recent_root = B256::repeat_byte(0x22);
3181 let mut parent = B256::ZERO;
3182
3183 for number in 0..=SNAPSHOT_STATE_RETENTION {
3184 let mut block = random_block(
3185 &mut rng,
3186 number,
3187 BlockParams { parent: Some(parent), tx_count: Some(0), ..Default::default() },
3188 )
3189 .unseal();
3190 block.header.state_root = match number {
3191 0 => expired_root,
3192 64 => recent_root,
3193 _ => EMPTY_ROOT_HASH,
3194 };
3195 let block = block.seal_slow();
3196 parent = block.hash();
3197 provider_rw
3198 .insert_block(&block.try_recover().expect("failed to seal block with senders"))?;
3199 }
3200 provider_rw.save_stage_checkpoint(
3201 StageId::Finish,
3202 StageCheckpoint::new(SNAPSHOT_STATE_RETENTION),
3203 )?;
3204 provider_rw.commit()?;
3205
3206 let provider = BlockchainProvider::new(factory)?;
3207 assert!(provider.state_range_provider(recent_root)?.is_some());
3208 assert!(provider.state_range_provider(expired_root)?.is_none());
3209
3210 Ok(())
3211 }
3212
3213 #[test]
3214 fn state_range_provider_serves_persisted_root_with_in_memory_overlay() -> eyre::Result<()> {
3215 let mut rng = generators::rng();
3216 let (provider, _, _, _) = provider_with_random_blocks(
3217 &mut rng,
3218 TEST_BLOCKS_COUNT - 1,
3219 1,
3220 BlockRangeParams::default(),
3221 )?;
3222 assert!(provider.canonical_in_memory_state.head_state().is_some());
3223 let provider_rw = provider.database.provider_rw()?;
3224 provider_rw.save_stage_checkpoint(
3225 StageId::Finish,
3226 StageCheckpoint::new((TEST_BLOCKS_COUNT - 2) as u64),
3227 )?;
3228 provider_rw.commit()?;
3229
3230 assert!(provider.state_range_provider(EMPTY_ROOT_HASH)?.is_some());
3231
3232 Ok(())
3233 }
3234
3235 #[test]
3236 fn state_range_provider_resolves_root_from_in_memory_block() -> eyre::Result<()> {
3237 let mut rng = generators::rng();
3238 let factory = test_provider_factory_with_genesis()?;
3239 let provider = BlockchainProvider::new(factory)?;
3240
3241 let (address, account) = random_account(1);
3242 let hashed_address = keccak256(address);
3243 let mut hashed_state = HashedPostState::default();
3244 hashed_state.accounts.insert(hashed_address, Some(account));
3245
3246 let unique_root = B256::repeat_byte(0x77);
3249 let parent = provider.canonical_in_memory_state.get_canonical_head();
3250 let mut block = random_block(
3251 &mut rng,
3252 parent.number + 1,
3253 BlockParams { parent: Some(parent.hash()), tx_count: Some(0), ..Default::default() },
3254 )
3255 .unseal();
3256 block.header.state_root = unique_root;
3257 let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3258
3259 let trie_data = ComputedTrieData::new(
3260 Arc::new(hashed_state.into_sorted()),
3261 Arc::new(TrieUpdates::default().into_sorted()),
3262 );
3263 let execution_output = BlockExecutionOutput {
3264 result: BlockExecutionResult {
3265 receipts: Default::default(),
3266 requests: Default::default(),
3267 gas_used: 0,
3268 blob_gas_used: 0,
3269 },
3270 state: Default::default(),
3271 };
3272 let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3273 provider.database.overlay_manager().insert_block(executed.clone());
3274 provider
3275 .canonical_in_memory_state
3276 .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3277
3278 let state =
3279 provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3280 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3281 assert_eq!(range.items, vec![(hashed_address, account)]);
3282
3283 Ok(())
3284 }
3285
3286 #[test]
3287 fn state_range_provider_reverts_database_advancement_past_anchor() -> eyre::Result<()> {
3288 let mut rng = generators::rng();
3289 let factory = test_provider_factory_with_genesis()?;
3290 let provider = BlockchainProvider::new(factory)?;
3291 let genesis = provider.canonical_in_memory_state.get_canonical_head();
3292
3293 let (target_address, target_account) = random_account(1);
3295 let target_hashed = keccak256(target_address);
3296 let mut target_state = HashedPostState::default();
3297 target_state.accounts.insert(target_hashed, Some(target_account));
3298
3299 let unique_root = B256::repeat_byte(0x77);
3300 let mut block = random_block(
3301 &mut rng,
3302 genesis.number + 1,
3303 BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3304 )
3305 .unseal();
3306 block.header.state_root = unique_root;
3307 let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3308 let trie_data = ComputedTrieData::new(
3309 Arc::new(target_state.into_sorted()),
3310 Arc::new(TrieUpdates::default().into_sorted()),
3311 );
3312 let execution_output = BlockExecutionOutput {
3313 result: BlockExecutionResult {
3314 receipts: Default::default(),
3315 requests: Default::default(),
3316 gas_used: 0,
3317 blob_gas_used: 0,
3318 },
3319 state: Default::default(),
3320 };
3321 let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3322 provider.database.overlay_manager().insert_block(executed.clone());
3323 provider
3324 .canonical_in_memory_state
3325 .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3326
3327 let (noise_address, noise_account) = random_account(2);
3331 let noise_block = random_block(
3332 &mut rng,
3333 genesis.number + 1,
3334 BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3335 )
3336 .try_recover()
3337 .expect("failed to seal block with senders");
3338 let mut noise_state = HashedPostState::default();
3339 noise_state.accounts.insert(keccak256(noise_address), Some(noise_account));
3340 let provider_rw = provider.database.provider_rw()?;
3341 provider_rw.append_blocks_with_state(
3342 vec![noise_block],
3343 &ExecutionOutcome {
3344 bundle: BundleState::new(
3345 [(noise_address, None, Some(noise_account.into()), Default::default())],
3346 [[(noise_address, Some(None), [])]],
3347 [],
3348 ),
3349 first_block: genesis.number + 1,
3350 ..Default::default()
3351 },
3352 noise_state.into_sorted(),
3353 )?;
3354 provider_rw
3355 .save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(genesis.number + 1))?;
3356 provider_rw.commit()?;
3357
3358 let state =
3361 provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3362 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3363 assert_eq!(range.items, vec![(target_hashed, target_account)]);
3364
3365 Ok(())
3366 }
3367
3368 #[test]
3369 fn historical_state_range_provider_reverts_state_change_past_retained_anchor(
3370 ) -> eyre::Result<()> {
3371 let mut rng = generators::rng();
3372
3373 let (address, account_a) = random_account(1);
3375 let hashed_address = keccak256(address);
3376 let slot_key = B256::with_last_byte(1);
3377 let slot = U256::from_be_bytes(slot_key.0);
3378 let hashed_slot = keccak256(slot_key);
3379 let value_a = U256::from(1);
3380
3381 let factory = test_provider_factory_with_genesis()?;
3382 let provider_rw = factory.provider_rw()?;
3383 provider_rw.insert_account_for_hashing([(address, Some(account_a))])?;
3384 provider_rw.insert_storage_for_hashing([(
3385 address,
3386 [StorageEntry { key: slot_key, value: value_a }],
3387 )])?;
3388 provider_rw.commit()?;
3389 let anchor_root = factory.latest()?.state_root(HashedPostState::default())?;
3390
3391 let genesis_hash = factory.sealed_header(0)?.unwrap().hash();
3392 let mut anchor_block = random_block(
3393 &mut rng,
3394 1,
3395 BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
3396 )
3397 .unseal();
3398 anchor_block.header.state_root = anchor_root;
3399 let anchor_block =
3400 anchor_block.seal_slow().try_recover().expect("failed to seal block with senders");
3401 let anchor_hash = anchor_block.hash();
3402
3403 let provider_rw = factory.provider_rw()?;
3404 provider_rw.insert_block(&anchor_block)?;
3405 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1))?;
3406 provider_rw.commit()?;
3407
3408 let account_b = Account { nonce: 2, balance: U256::from(2), ..account_a };
3410 let value_b = U256::from(2);
3411
3412 let mut storage = HashMap::default();
3413 storage.insert(slot, (value_a, value_b));
3414
3415 let mut state_b = HashedPostState::default();
3416 state_b.accounts.insert(hashed_address, Some(account_b));
3417 state_b.storages.insert(hashed_address, HashedStorage::from_iter([(hashed_slot, value_b)]));
3418
3419 let state_b_root = factory.latest()?.state_root(state_b.clone())?;
3420 let mut later_block = random_block(
3421 &mut rng,
3422 2,
3423 BlockParams { parent: Some(anchor_hash), tx_count: Some(0), ..Default::default() },
3424 )
3425 .unseal();
3426 later_block.header.state_root = state_b_root;
3427 let later_block =
3428 later_block.seal_slow().try_recover().expect("failed to seal block with senders");
3429
3430 let provider_rw = factory.provider_rw()?;
3431 provider_rw.append_blocks_with_state(
3432 vec![later_block],
3433 &ExecutionOutcome {
3434 bundle: BundleState::new(
3435 [(address, Some(account_a.into()), Some(account_b.into()), storage)],
3436 [[(address, Some(Some(account_a.into())), [(slot, value_a)])]],
3437 [],
3438 ),
3439 first_block: 2,
3440 ..Default::default()
3441 },
3442 state_b.into_sorted(),
3443 )?;
3444 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(2))?;
3445 provider_rw.commit()?;
3446
3447 let provider = BlockchainProvider::new(factory)?;
3450 let state =
3451 provider.state_range_provider(anchor_root)?.expect("retained root must resolve");
3452 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3453 assert_eq!(range.items, vec![(hashed_address, account_a)]);
3454
3455 let storage_range = state
3456 .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3457 .expect("account must have storage");
3458 assert_eq!(storage_range.items, vec![(hashed_slot, value_a)]);
3459
3460 Ok(())
3461 }
3462}