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 const TEST_BLOCKS_COUNT: usize = 5;
1084
1085 const TEST_TRANSACTIONS_COUNT: u8 = 4;
1086
1087 fn random_blocks(
1088 rng: &mut impl Rng,
1089 database_blocks: usize,
1090 in_memory_blocks: usize,
1091 requests_count: Option<Range<u8>>,
1092 withdrawals_count: Option<Range<u8>>,
1093 tx_count: impl RangeBounds<u8>,
1094 ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1095 let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1096
1097 let tx_start = match tx_count.start_bound() {
1098 Bound::Included(&n) | Bound::Excluded(&n) => n,
1099 Bound::Unbounded => u8::MIN,
1100 };
1101 let tx_end = match tx_count.end_bound() {
1102 Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1103 Bound::Unbounded => u8::MAX,
1104 };
1105
1106 let blocks = random_block_range(
1107 rng,
1108 0..=block_range,
1109 BlockRangeParams {
1110 parent: Some(B256::ZERO),
1111 tx_count: tx_start..tx_end,
1112 requests_count,
1113 withdrawals_count,
1114 },
1115 );
1116 let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1117 (database_blocks.to_vec(), in_memory_blocks.to_vec())
1118 }
1119
1120 #[expect(clippy::type_complexity)]
1121 fn provider_with_chain_spec_and_random_blocks(
1122 rng: &mut impl Rng,
1123 chain_spec: Arc<ChainSpec>,
1124 database_blocks: usize,
1125 in_memory_blocks: usize,
1126 block_range_params: BlockRangeParams,
1127 ) -> eyre::Result<(
1128 BlockchainProvider<MockNodeTypesWithDB>,
1129 Vec<SealedBlock<Block>>,
1130 Vec<SealedBlock<Block>>,
1131 Vec<Vec<Receipt>>,
1132 )> {
1133 let (database_blocks, in_memory_blocks) = random_blocks(
1134 rng,
1135 database_blocks,
1136 in_memory_blocks,
1137 block_range_params.requests_count,
1138 block_range_params.withdrawals_count,
1139 block_range_params.tx_count,
1140 );
1141
1142 let receipts: Vec<Vec<_>> = database_blocks
1143 .iter()
1144 .chain(in_memory_blocks.iter())
1145 .map(|block| block.body().transactions.iter())
1146 .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
1147 .collect();
1148
1149 let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1150 let provider_rw = factory.database_provider_rw()?;
1151
1152 for block in &database_blocks {
1154 provider_rw.insert_block(
1155 &block.clone().try_recover().expect("failed to seal block with senders"),
1156 )?;
1157 }
1158
1159 if let Some(first_block) = database_blocks.first() {
1161 provider_rw.write_state(
1162 &ExecutionOutcome {
1163 first_block: first_block.number,
1164 receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
1165 ..Default::default()
1166 },
1167 OriginalValuesKnown::No,
1168 StateWriteConfig::default(),
1169 )?;
1170 }
1171
1172 provider_rw.commit()?;
1173
1174 let provider = BlockchainProvider::new(factory)?;
1175
1176 let chain = NewCanonicalChain::Commit {
1178 new: in_memory_blocks
1179 .iter()
1180 .map(|block| {
1181 let senders = block.senders().expect("failed to recover senders");
1182 let block_receipts = receipts.get(block.number as usize).unwrap().clone();
1183 let execution_outcome = BlockExecutionOutput {
1184 result: BlockExecutionResult {
1185 receipts: block_receipts,
1186 requests: Default::default(),
1187 gas_used: 0,
1188 blob_gas_used: 0,
1189 },
1190 state: BundleState::default(),
1191 };
1192
1193 ExecutedBlock {
1194 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1195 block.clone(),
1196 senders,
1197 )),
1198 execution_output: execution_outcome.into(),
1199 ..Default::default()
1200 }
1201 })
1202 .collect(),
1203 };
1204 provider.canonical_in_memory_state.update_chain(chain);
1205 for state in provider.canonical_in_memory_state.canonical_chain() {
1206 provider.database.overlay_manager().insert_block(state.block());
1207 }
1208
1209 let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
1211 let block_count = blocks.len();
1212 let canonical_block = blocks.get(block_count - 1).unwrap();
1213 let safe_block = blocks.get(block_count - 2).unwrap();
1214 let finalized_block = blocks.get(block_count - 3).unwrap();
1215
1216 provider.set_canonical_head(canonical_block.clone_sealed_header());
1218 provider.set_safe(safe_block.clone_sealed_header());
1219 provider.set_finalized(finalized_block.clone_sealed_header());
1220
1221 Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
1222 }
1223
1224 #[expect(clippy::type_complexity)]
1225 fn provider_with_random_blocks(
1226 rng: &mut impl Rng,
1227 database_blocks: usize,
1228 in_memory_blocks: usize,
1229 block_range_params: BlockRangeParams,
1230 ) -> eyre::Result<(
1231 BlockchainProvider<MockNodeTypesWithDB>,
1232 Vec<SealedBlock<Block>>,
1233 Vec<SealedBlock<Block>>,
1234 Vec<Vec<Receipt>>,
1235 )> {
1236 provider_with_chain_spec_and_random_blocks(
1237 rng,
1238 MAINNET.clone(),
1239 database_blocks,
1240 in_memory_blocks,
1241 block_range_params,
1242 )
1243 }
1244
1245 fn persist_block_after_db_tx_creation(
1251 provider: BlockchainProvider<MockNodeTypesWithDB>,
1252 block_number: BlockNumber,
1253 ) {
1254 let hook_provider = provider.clone();
1255 provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
1256 if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
1257 state.anchor().number + 1 == block_number
1258 {
1259 let mut lowest_memory_block =
1260 state.parent_state_chain().last().expect("qed").block();
1261 let num_hash = lowest_memory_block.recovered_block().num_hash();
1262
1263 let execution_output = (*lowest_memory_block.execution_output).clone();
1264 lowest_memory_block.execution_output = Arc::new(execution_output);
1265
1266 let provider_rw = hook_provider.database_provider_rw().unwrap();
1268 let input = SaveBlocksInput::new(
1269 vec![lowest_memory_block],
1270 state.anchor().number,
1271 state.anchor().number,
1272 block_number,
1273 block_number,
1274 );
1275 provider_rw.save_blocks(&input).unwrap();
1276 provider_rw.commit().unwrap();
1277
1278 hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
1280 }
1281 }));
1282 }
1283
1284 #[test]
1285 fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1286 let mut rng = generators::rng();
1288 let factory = create_test_provider_factory();
1289
1290 let blocks = random_block_range(
1292 &mut rng,
1293 0..=10,
1294 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1295 );
1296 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1297
1298 let provider_rw = factory.provider_rw()?;
1300 for block in database_blocks {
1301 provider_rw.insert_block(
1302 &block.clone().try_recover().expect("failed to seal block with senders"),
1303 )?;
1304 }
1305
1306 provider_rw.commit()?;
1307
1308 let provider = BlockchainProvider::new(factory)?;
1310
1311 let first_db_block = database_blocks.first().unwrap();
1313 let first_in_mem_block = in_memory_blocks.first().unwrap();
1314 let last_in_mem_block = in_memory_blocks.last().unwrap();
1315
1316 assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1318 assert_eq!(
1319 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1320 None
1321 );
1322 assert_eq!(
1324 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1325 None
1326 );
1327
1328 let in_memory_block_senders =
1330 first_in_mem_block.senders().expect("failed to recover senders");
1331 let chain = NewCanonicalChain::Commit {
1332 new: vec![ExecutedBlock {
1333 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1334 first_in_mem_block.clone(),
1335 in_memory_block_senders,
1336 )),
1337 ..Default::default()
1338 }],
1339 };
1340 provider.canonical_in_memory_state.update_chain(chain);
1341
1342 assert_eq!(
1344 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1345 Some(first_in_mem_block.clone().into_block())
1346 );
1347 assert_eq!(
1348 provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1349 Some(first_in_mem_block.clone().into_block())
1350 );
1351
1352 assert_eq!(
1354 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1355 Some(first_db_block.clone().into_block())
1356 );
1357 assert_eq!(
1358 provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1359 Some(first_db_block.clone().into_block())
1360 );
1361
1362 assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1364
1365 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1367 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1368 last_in_mem_block.clone(),
1369 Default::default(),
1370 )),
1371 ..Default::default()
1372 });
1373
1374 assert_eq!(
1376 provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1377 Some(last_in_mem_block.clone().into_block())
1378 );
1379
1380 Ok(())
1381 }
1382
1383 #[test]
1384 fn test_block_reader_block() -> eyre::Result<()> {
1385 let mut rng = generators::rng();
1387 let factory = create_test_provider_factory();
1388
1389 let blocks = random_block_range(
1391 &mut rng,
1392 0..=10,
1393 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1394 );
1395 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1396
1397 let provider_rw = factory.provider_rw()?;
1399 for block in database_blocks {
1400 provider_rw.insert_block(
1401 &block.clone().try_recover().expect("failed to seal block with senders"),
1402 )?;
1403 }
1404 provider_rw.commit()?;
1405
1406 let provider = BlockchainProvider::new(factory)?;
1408
1409 let first_in_mem_block = in_memory_blocks.first().unwrap();
1411 let first_db_block = database_blocks.first().unwrap();
1413
1414 assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1416 assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1417
1418 let in_memory_block_senders =
1420 first_in_mem_block.senders().expect("failed to recover senders");
1421 let chain = NewCanonicalChain::Commit {
1422 new: vec![ExecutedBlock {
1423 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1424 first_in_mem_block.clone(),
1425 in_memory_block_senders,
1426 )),
1427 ..Default::default()
1428 }],
1429 };
1430 provider.canonical_in_memory_state.update_chain(chain);
1431
1432 assert_eq!(
1434 provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1435 Some(first_in_mem_block.clone().into_block())
1436 );
1437 assert_eq!(
1438 provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1439 Some(first_in_mem_block.clone().into_block())
1440 );
1441
1442 assert_eq!(
1444 provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1445 Some(first_db_block.clone().into_block())
1446 );
1447 assert_eq!(
1448 provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1449 Some(first_db_block.clone().into_block())
1450 );
1451
1452 Ok(())
1453 }
1454
1455 #[test]
1456 fn test_block_reader_pending_block() -> eyre::Result<()> {
1457 let mut rng = generators::rng();
1458 let (provider, _, _, _) = provider_with_random_blocks(
1459 &mut rng,
1460 TEST_BLOCKS_COUNT,
1461 TEST_BLOCKS_COUNT,
1462 BlockRangeParams::default(),
1463 )?;
1464
1465 let mut rng = generators::rng();
1467 let block = random_block(
1468 &mut rng,
1469 0,
1470 BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1471 );
1472
1473 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1475 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1476 block.clone(),
1477 block.senders().unwrap(),
1478 )),
1479 ..Default::default()
1480 });
1481
1482 assert_eq!(
1485 provider.pending_block()?,
1486 Some(RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()))
1487 );
1488
1489 assert_eq!(
1490 provider.pending_block_and_receipts()?,
1491 Some((RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()), vec![]))
1492 );
1493
1494 Ok(())
1495 }
1496
1497 #[test]
1498 fn test_block_body_indices() -> eyre::Result<()> {
1499 let mut rng = generators::rng();
1501 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1502 &mut rng,
1503 TEST_BLOCKS_COUNT,
1504 TEST_BLOCKS_COUNT,
1505 BlockRangeParams {
1506 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1507 ..Default::default()
1508 },
1509 )?;
1510
1511 let first_in_mem_block = in_memory_blocks.first().unwrap();
1512
1513 let in_memory_block_senders =
1515 first_in_mem_block.senders().expect("failed to recover senders");
1516 let chain = NewCanonicalChain::Commit {
1517 new: vec![ExecutedBlock {
1518 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1519 first_in_mem_block.clone(),
1520 in_memory_block_senders,
1521 )),
1522 ..Default::default()
1523 }],
1524 };
1525 provider.canonical_in_memory_state.update_chain(chain);
1526
1527 let first_db_block = database_blocks.first().unwrap().clone();
1528 let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1529
1530 assert_eq!(
1532 provider.block_body_indices(first_db_block.number)?.unwrap(),
1533 StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1534 );
1535
1536 assert_eq!(
1539 provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1540 StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1541 );
1542
1543 let mut rng = rand::rng();
1545 let random_block_number: u64 = rng.random();
1546 assert_eq!(provider.block_body_indices(random_block_number)?, None);
1547
1548 Ok(())
1549 }
1550
1551 #[test]
1552 fn test_block_hash_reader() -> eyre::Result<()> {
1553 let mut rng = generators::rng();
1554 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1555 &mut rng,
1556 TEST_BLOCKS_COUNT,
1557 TEST_BLOCKS_COUNT,
1558 BlockRangeParams::default(),
1559 )?;
1560
1561 let database_block = database_blocks.first().unwrap().clone();
1562 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1563
1564 assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1565 assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1566
1567 assert_eq!(
1568 provider.canonical_hashes_range(0, 10)?,
1569 [database_blocks, in_memory_blocks]
1570 .concat()
1571 .iter()
1572 .map(|block| block.hash())
1573 .collect::<Vec<_>>()
1574 );
1575
1576 Ok(())
1577 }
1578
1579 #[test]
1580 fn test_header_provider() -> eyre::Result<()> {
1581 let mut rng = generators::rng();
1582 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1583 &mut rng,
1584 TEST_BLOCKS_COUNT,
1585 TEST_BLOCKS_COUNT,
1586 BlockRangeParams::default(),
1587 )?;
1588
1589 let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1591 provider.set_finalized(finalized_block.clone_sealed_header());
1592
1593 let blocks = [database_blocks, in_memory_blocks].concat();
1594
1595 assert_eq!(
1596 provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1597 blocks
1598 .iter()
1599 .take_while(|header| header.number <= 8)
1600 .map(|b| b.clone_sealed_header())
1601 .collect::<Vec<_>>()
1602 );
1603
1604 Ok(())
1605 }
1606
1607 #[tokio::test]
1608 async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1609 let factory = create_test_provider_factory();
1610
1611 let mut test_block_builder = TestBlockBuilder::eth();
1613 let block_1 = test_block_builder.generate_random_block(0, B256::ZERO).try_recover()?;
1614 let block_hash_1 = block_1.hash();
1615
1616 let provider_rw = factory.provider_rw()?;
1618 provider_rw.insert_block(&block_1)?;
1619 provider_rw.commit()?;
1620
1621 let provider = BlockchainProvider::new(factory)?;
1622
1623 let in_memory_state = provider.canonical_in_memory_state();
1625 let mut rx_1 = provider.subscribe_to_canonical_state();
1626 let mut rx_2 = provider.subscribe_to_canonical_state();
1627
1628 let block_2 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1630 let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), BTreeMap::new());
1631 let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1632 in_memory_state.notify_canon_state(commit.clone());
1633 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1634 assert_eq!(notification_1, Ok(commit.clone()));
1635 assert_eq!(notification_2, Ok(commit.clone()));
1636
1637 let block_3 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1639 let block_4 = test_block_builder.generate_random_block(2, block_3.hash()).try_recover()?;
1640 let new_chain =
1641 Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), BTreeMap::new());
1642 let re_org =
1643 CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1644 in_memory_state.notify_canon_state(re_org.clone());
1645 let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1646 assert_eq!(notification_1, Ok(re_org.clone()));
1647 assert_eq!(notification_2, Ok(re_org.clone()));
1648
1649 Ok(())
1650 }
1651
1652 #[test]
1653 fn test_block_num_reader() -> eyre::Result<()> {
1654 let mut rng = generators::rng();
1655 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1656 &mut rng,
1657 TEST_BLOCKS_COUNT,
1658 TEST_BLOCKS_COUNT,
1659 BlockRangeParams::default(),
1660 )?;
1661
1662 assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1663 assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1664
1665 let database_block = database_blocks.first().unwrap().clone();
1666 let in_memory_block = in_memory_blocks.first().unwrap().clone();
1667 assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1668 assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1669
1670 Ok(())
1671 }
1672
1673 #[test]
1674 fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1675 let mut rng = generators::rng();
1676 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1677 &mut rng,
1678 TEST_BLOCKS_COUNT,
1679 TEST_BLOCKS_COUNT,
1680 BlockRangeParams::default(),
1681 )?;
1682
1683 let database_block = database_blocks.first().unwrap().clone();
1684 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1685
1686 let block_number = database_block.number;
1687 let block_hash = database_block.hash();
1688
1689 assert_eq!(
1690 provider.block_by_id(block_number.into()).unwrap(),
1691 Some(database_block.clone().into_block())
1692 );
1693 assert_eq!(
1694 provider.block_by_id(block_hash.into()).unwrap(),
1695 Some(database_block.into_block())
1696 );
1697
1698 let block_number = in_memory_block.number;
1699 let block_hash = in_memory_block.hash();
1700 assert_eq!(
1701 provider.block_by_id(block_number.into()).unwrap(),
1702 Some(in_memory_block.clone().into_block())
1703 );
1704 assert_eq!(
1705 provider.block_by_id(block_hash.into()).unwrap(),
1706 Some(in_memory_block.into_block())
1707 );
1708
1709 Ok(())
1710 }
1711
1712 #[test]
1713 fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1714 let mut rng = generators::rng();
1715 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1716 &mut rng,
1717 TEST_BLOCKS_COUNT,
1718 TEST_BLOCKS_COUNT,
1719 BlockRangeParams::default(),
1720 )?;
1721
1722 let database_block = database_blocks.first().unwrap().clone();
1723
1724 let in_memory_block_count = in_memory_blocks.len();
1725 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1726 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1727 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1728
1729 let block_number = database_block.number;
1730 assert_eq!(
1731 provider.header_by_number_or_tag(block_number.into()).unwrap(),
1732 Some(database_block.header().clone())
1733 );
1734 assert_eq!(
1735 provider.sealed_header_by_number_or_tag(block_number.into())?,
1736 Some(database_block.clone_sealed_header())
1737 );
1738
1739 assert_eq!(
1740 provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1741 Some(canonical_block.header().clone())
1742 );
1743 assert_eq!(
1744 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1745 Some(canonical_block.clone_sealed_header())
1746 );
1747
1748 assert_eq!(
1749 provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1750 Some(safe_block.header().clone())
1751 );
1752 assert_eq!(
1753 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1754 Some(safe_block.clone_sealed_header())
1755 );
1756
1757 assert_eq!(
1758 provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1759 Some(finalized_block.header().clone())
1760 );
1761 assert_eq!(
1762 provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1763 Some(finalized_block.clone_sealed_header())
1764 );
1765
1766 Ok(())
1767 }
1768
1769 #[test]
1770 fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1771 let mut rng = generators::rng();
1772 let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1773 &mut rng,
1774 TEST_BLOCKS_COUNT,
1775 TEST_BLOCKS_COUNT,
1776 BlockRangeParams::default(),
1777 )?;
1778
1779 let database_block = database_blocks.first().unwrap().clone();
1780 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1781
1782 let block_number = database_block.number;
1783 let block_hash = database_block.hash();
1784
1785 assert_eq!(
1786 provider.header_by_id(block_number.into()).unwrap(),
1787 Some(database_block.header().clone())
1788 );
1789 assert_eq!(
1790 provider.sealed_header_by_id(block_number.into()).unwrap(),
1791 Some(database_block.clone_sealed_header())
1792 );
1793
1794 assert_eq!(
1795 provider.header_by_id(block_hash.into()).unwrap(),
1796 Some(database_block.header().clone())
1797 );
1798 assert_eq!(
1799 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1800 Some(database_block.clone_sealed_header())
1801 );
1802
1803 let block_number = in_memory_block.number;
1804 let block_hash = in_memory_block.hash();
1805
1806 assert_eq!(
1807 provider.header_by_id(block_number.into()).unwrap(),
1808 Some(in_memory_block.header().clone())
1809 );
1810 assert_eq!(
1811 provider.sealed_header_by_id(block_number.into()).unwrap(),
1812 Some(in_memory_block.clone_sealed_header())
1813 );
1814
1815 assert_eq!(
1816 provider.header_by_id(block_hash.into()).unwrap(),
1817 Some(in_memory_block.header().clone())
1818 );
1819 assert_eq!(
1820 provider.sealed_header_by_id(block_hash.into()).unwrap(),
1821 Some(in_memory_block.clone_sealed_header())
1822 );
1823
1824 Ok(())
1825 }
1826
1827 #[test]
1828 fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
1829 let mut rng = generators::rng();
1830 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1831 &mut rng,
1832 TEST_BLOCKS_COUNT,
1833 TEST_BLOCKS_COUNT,
1834 BlockRangeParams { tx_count: 1..3, ..Default::default() },
1835 )?;
1836
1837 let database_block = database_blocks.first().unwrap().clone();
1838 let in_memory_block = in_memory_blocks.last().unwrap().clone();
1839
1840 let block_number = database_block.number;
1841 let block_hash = database_block.hash();
1842
1843 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1844 assert!(!provider
1845 .receipts_by_number_or_tag(database_block.number.into())?
1846 .unwrap()
1847 .is_empty());
1848
1849 assert_eq!(
1850 provider.receipts_by_block_id(block_number.into())?.unwrap(),
1851 receipts.get(block_number as usize).unwrap().clone()
1852 );
1853 assert_eq!(
1854 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1855 receipts.get(block_number as usize).unwrap().clone()
1856 );
1857
1858 let block_number = in_memory_block.number;
1859 let block_hash = in_memory_block.hash();
1860
1861 assert_eq!(
1862 provider.receipts_by_block_id(block_number.into())?.unwrap(),
1863 receipts.get(block_number as usize).unwrap().clone()
1864 );
1865 assert_eq!(
1866 provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1867 receipts.get(block_number as usize).unwrap().clone()
1868 );
1869
1870 Ok(())
1871 }
1872
1873 #[test]
1874 fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
1875 let mut rng = generators::rng();
1876 let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1877 &mut rng,
1878 TEST_BLOCKS_COUNT,
1879 TEST_BLOCKS_COUNT,
1880 BlockRangeParams { tx_count: 1..3, ..Default::default() },
1881 )?;
1882
1883 let database_block = database_blocks.first().unwrap().clone();
1884
1885 let in_memory_block_count = in_memory_blocks.len();
1886 let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1887 let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1888 let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1889
1890 assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1891 assert!(!provider
1892 .receipts_by_number_or_tag(database_block.number.into())?
1893 .unwrap()
1894 .is_empty());
1895
1896 assert_eq!(
1897 provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
1898 receipts.get(database_block.number as usize).unwrap().clone()
1899 );
1900 assert_eq!(
1901 provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
1902 receipts.get(canonical_block.number as usize).unwrap().clone()
1903 );
1904 assert_eq!(
1905 provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
1906 receipts.get(safe_block.number as usize).unwrap().clone()
1907 );
1908 assert_eq!(
1909 provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
1910 receipts.get(finalized_block.number as usize).unwrap().clone()
1911 );
1912
1913 Ok(())
1914 }
1915
1916 #[test]
1917 fn test_changeset_reader() -> eyre::Result<()> {
1918 let mut rng = generators::rng();
1919
1920 let (database_blocks, in_memory_blocks) =
1921 random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1922
1923 let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1924 let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1925 let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1926
1927 let accounts = random_eoa_accounts(&mut rng, 2);
1928
1929 let (database_changesets, database_state) = random_changeset_range(
1930 &mut rng,
1931 &database_blocks,
1932 accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1933 0..0,
1934 0..0,
1935 );
1936 let (in_memory_changesets, in_memory_state) = random_changeset_range(
1937 &mut rng,
1938 &in_memory_blocks,
1939 database_state
1940 .iter()
1941 .map(|(address, (account, storage))| (*address, (*account, storage.clone()))),
1942 0..0,
1943 0..0,
1944 );
1945
1946 let factory = create_test_provider_factory();
1947
1948 let provider_rw = factory.provider_rw()?;
1949 provider_rw.append_blocks_with_state(
1950 database_blocks
1951 .into_iter()
1952 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1953 .collect(),
1954 &ExecutionOutcome {
1955 bundle: BundleState::new(
1956 database_state.into_iter().map(|(address, (account, _))| {
1957 (address, None, Some(account.into()), Default::default())
1958 }),
1959 database_changesets.iter().map(|block_changesets| {
1960 block_changesets.iter().map(|(address, account, _)| {
1961 (*address, Some(Some((*account).into())), [])
1962 })
1963 }),
1964 Vec::new(),
1965 ),
1966 first_block: first_database_block,
1967 ..Default::default()
1968 },
1969 Default::default(),
1970 )?;
1971 provider_rw.commit()?;
1972
1973 let provider = BlockchainProvider::new(factory)?;
1974
1975 let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1976 let chain = NewCanonicalChain::Commit {
1977 new: vec![in_memory_blocks
1978 .first()
1979 .map(|block| {
1980 let senders = block.senders().expect("failed to recover senders");
1981 ExecutedBlock {
1982 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1983 block.clone(),
1984 senders,
1985 )),
1986 execution_output: Arc::new(BlockExecutionOutput {
1987 state: BundleState::new(
1988 in_memory_state.into_iter().map(|(address, (account, _))| {
1989 (address, None, Some(account.into()), Default::default())
1990 }),
1991 [in_memory_changesets.iter().map(|(address, account, _)| {
1992 (*address, Some(Some((*account).into())), Vec::new())
1993 })],
1994 [],
1995 ),
1996 result: BlockExecutionResult {
1997 receipts: Default::default(),
1998 requests: Default::default(),
1999 gas_used: 0,
2000 blob_gas_used: 0,
2001 },
2002 }),
2003 ..Default::default()
2004 }
2005 })
2006 .unwrap()],
2007 };
2008 provider.canonical_in_memory_state.update_chain(chain);
2009
2010 assert_eq!(
2011 provider.account_block_changeset(last_database_block).unwrap(),
2012 database_changesets
2013 .into_iter()
2014 .next_back()
2015 .unwrap()
2016 .into_iter()
2017 .sorted_by_key(|(address, _, _)| *address)
2018 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2019 .collect::<Vec<_>>()
2020 );
2021 assert_eq!(
2022 provider.account_block_changeset(first_in_memory_block).unwrap(),
2023 in_memory_changesets
2024 .into_iter()
2025 .sorted_by_key(|(address, _, _)| *address)
2026 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2027 .collect::<Vec<_>>()
2028 );
2029
2030 Ok(())
2031 }
2032
2033 #[test]
2034 fn test_state_provider_factory() -> eyre::Result<()> {
2035 let mut rng = generators::rng();
2036
2037 let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2039 &mut rng,
2040 TEST_BLOCKS_COUNT,
2041 TEST_BLOCKS_COUNT,
2042 BlockRangeParams::default(),
2043 )?;
2044
2045 let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
2047 &mut rng,
2048 TEST_BLOCKS_COUNT,
2049 0,
2050 BlockRangeParams::default(),
2051 )?;
2052
2053 let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
2054 let first_in_memory_block = in_memory_blocks.first().unwrap();
2055 let first_db_block = database_blocks.first().unwrap();
2056
2057 assert_eq!(
2059 first_in_memory_block.hash(),
2060 in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
2061 );
2062 assert_eq!(
2064 first_db_block.hash(),
2065 only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
2066 );
2067
2068 assert_eq!(
2070 first_in_memory_block.hash(),
2071 in_memory_provider
2072 .history_by_block_number(first_in_memory_block.number)?
2073 .block_hash(first_in_memory_block.number)?
2074 .unwrap()
2075 );
2076 assert_eq!(
2077 first_db_block.hash(),
2078 only_database_provider
2079 .history_by_block_number(first_db_block.number)?
2080 .block_hash(first_db_block.number)?
2081 .unwrap()
2082 );
2083 assert_eq!(
2084 first_in_memory_block.hash(),
2085 in_memory_provider
2086 .history_by_block_hash(first_in_memory_block.hash())?
2087 .block_hash(first_in_memory_block.number)?
2088 .unwrap()
2089 );
2090 assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
2091
2092 assert_eq!(
2094 first_in_memory_block.hash(),
2095 in_memory_provider
2096 .state_by_block_hash(first_in_memory_block.hash())?
2097 .block_hash(first_in_memory_block.number)?
2098 .unwrap()
2099 );
2100 assert_eq!(
2101 first_db_block.hash(),
2102 only_database_provider
2103 .state_by_block_hash(first_db_block.hash())?
2104 .block_hash(first_db_block.number)?
2105 .unwrap()
2106 );
2107 assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
2108
2109 assert_eq!(
2111 first_in_memory_block.hash(),
2112 in_memory_provider
2113 .pending()
2114 .unwrap()
2115 .block_hash(first_in_memory_block.number)
2116 .unwrap()
2117 .unwrap()
2118 );
2119
2120 let pending_block = database_blocks[database_blocks.len() - 1].clone();
2122 only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2123 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2124 pending_block.clone(),
2125 Default::default(),
2126 )),
2127 ..Default::default()
2128 });
2129
2130 assert_eq!(
2131 pending_block.hash(),
2132 only_database_provider
2133 .pending()
2134 .unwrap()
2135 .block_hash(pending_block.number)
2136 .unwrap()
2137 .unwrap()
2138 );
2139
2140 assert_eq!(
2141 pending_block.hash(),
2142 only_database_provider
2143 .pending_state_by_hash(pending_block.hash())?
2144 .unwrap()
2145 .block_hash(pending_block.number)?
2146 .unwrap()
2147 );
2148
2149 assert_eq!(
2151 first_in_memory_block.hash(),
2152 in_memory_provider
2153 .state_by_block_number_or_tag(BlockNumberOrTag::Number(
2154 first_in_memory_block.number
2155 ))?
2156 .block_hash(first_in_memory_block.number)?
2157 .unwrap()
2158 );
2159 assert_eq!(
2160 first_in_memory_block.hash(),
2161 in_memory_provider
2162 .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
2163 .block_hash(first_in_memory_block.number)?
2164 .unwrap()
2165 );
2166 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2168 in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2169 assert_eq!(
2170 safe_block.hash(),
2171 in_memory_provider
2172 .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
2173 .block_hash(safe_block.number)?
2174 .unwrap()
2175 );
2176 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2178 in_memory_provider
2179 .canonical_in_memory_state
2180 .set_finalized(finalized_block.clone_sealed_header());
2181 assert_eq!(
2182 finalized_block.hash(),
2183 in_memory_provider
2184 .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
2185 .block_hash(finalized_block.number)?
2186 .unwrap()
2187 );
2188 let earliest_block = blocks.first().unwrap().clone();
2190 assert_eq!(
2191 earliest_block.hash(),
2192 only_database_provider
2193 .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
2194 .block_hash(earliest_block.number)?
2195 .unwrap()
2196 );
2197
2198 Ok(())
2199 }
2200
2201 #[test]
2202 fn test_block_id_reader() -> eyre::Result<()> {
2203 let mut rng = generators::rng();
2205 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2206 &mut rng,
2207 TEST_BLOCKS_COUNT,
2208 TEST_BLOCKS_COUNT,
2209 BlockRangeParams::default(),
2210 )?;
2211
2212 let pending_block = in_memory_blocks.last().unwrap();
2214 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2215 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2216 pending_block.clone(),
2217 Default::default(),
2218 )),
2219 ..Default::default()
2220 });
2221
2222 let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2224 provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2225
2226 let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2228 provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
2229
2230 assert_eq!(
2232 provider.pending_block_num_hash()?,
2233 Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
2234 );
2235
2236 assert_eq!(
2238 provider.safe_block_num_hash()?,
2239 Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
2240 );
2241
2242 assert_eq!(
2244 provider.finalized_block_num_hash()?,
2245 Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
2246 );
2247
2248 Ok(())
2249 }
2250
2251 macro_rules! test_by_tx_range {
2252 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2253
2254 let extra_blocks = [$(stringify!($method)),*].len();
2257
2258 let mut rng = generators::rng();
2259 let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
2260 &mut rng,
2261 TEST_BLOCKS_COUNT,
2262 TEST_BLOCKS_COUNT + extra_blocks,
2263 BlockRangeParams {
2264 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2265 ..Default::default()
2266 },
2267 )?;
2268
2269 $(
2270 let db_tx_count =
2272 database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2273 let in_mem_tx_count =
2274 in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2275
2276 let db_range = 0..=(db_tx_count - 1);
2277 let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
2278
2279 let database_data =
2281 database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2282 assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
2283
2284 let in_memory_data =
2286 in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2287 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
2288
2289 assert_eq!(
2291 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2292 &in_memory_data[1..in_memory_data.len() - 1],
2293 "partial mem data"
2294 );
2295
2296 assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
2298
2299 assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
2301
2302 assert_eq!(
2304 provider.$method(in_mem_range.start() - 2..)?,
2305 database_data[database_data.len() - 2..]
2306 .iter()
2307 .chain(&in_memory_data[..])
2308 .cloned()
2309 .collect::<Vec<_>>(),
2310 "unbounded span data"
2311 );
2312
2313 {
2315 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2317
2318 assert_eq!(
2319 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2320 database_data[database_data.len() - 2..]
2321 .iter()
2322 .chain(&in_memory_data[..in_memory_data.len() - 1])
2323 .cloned()
2324 .collect::<Vec<_>>(),
2325 "span data"
2326 );
2327
2328 database_blocks.push(in_memory_blocks.remove(0));
2330 }
2331
2332 let start_tx_num = u64::MAX;
2334 let end_tx_num = u64::MAX;
2335 let result = provider.$method(start_tx_num..end_tx_num)?;
2336 assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2337
2338 let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2340 assert!(result.is_empty(), "No data should be found for an empty transaction range");
2341 )*
2342 }};
2343 }
2344
2345 #[test]
2346 fn test_methods_by_tx_range() -> eyre::Result<()> {
2347 test_by_tx_range!([
2348 (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2349 .senders()
2350 .unwrap()),
2351 (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2352 .body()
2353 .transactions
2354 .clone()),
2355 (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2356 receipts[block.number as usize].clone()
2357 })
2358 ]);
2359
2360 Ok(())
2361 }
2362
2363 macro_rules! test_by_block_range {
2364 ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2365 let extra_blocks = [$(stringify!($method)),*].len();
2368
2369 let mut rng = generators::rng();
2370 let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2371 &mut rng,
2372 TEST_BLOCKS_COUNT,
2373 TEST_BLOCKS_COUNT + extra_blocks,
2374 BlockRangeParams {
2375 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2376 ..Default::default()
2377 },
2378 )?;
2379
2380 $(
2381 let db_block_count = database_blocks.len() as u64;
2383 let in_mem_block_count = in_memory_blocks.len() as u64;
2384
2385 let db_range = 0..=db_block_count - 1;
2386 let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2387
2388 let database_data =
2390 database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2391 assert_eq!(provider.$method(db_range.clone())?, database_data);
2392
2393 let in_memory_data =
2395 in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2396 assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2397
2398 assert_eq!(
2400 &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2401 &in_memory_data[1..in_memory_data.len() - 1]
2402 );
2403
2404 {
2406
2407 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2409
2410 assert_eq!(
2411 provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2412 database_data[database_data.len() - 2..]
2413 .iter()
2414 .chain(&in_memory_data[..in_memory_data.len() - 1])
2415 .cloned()
2416 .collect::<Vec<_>>()
2417 );
2418
2419 database_blocks.push(in_memory_blocks.remove(0));
2421 }
2422
2423 let start_block_num = u64::MAX;
2425 let end_block_num = u64::MAX;
2426 let result = provider.$method(start_block_num..=end_block_num-1)?;
2427 assert!(result.is_empty(), "No data should be found for an invalid block range");
2428
2429 let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2431 assert!(result.is_empty(), "No data should be found for an empty block range");
2432 )*
2433 }};
2434 }
2435
2436 #[test]
2437 fn test_methods_by_block_range() -> eyre::Result<()> {
2438 test_by_block_range!([
2441 (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2442 (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2443 (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2444 (block_with_senders_range, |block: &SealedBlock<Block>| block
2445 .clone()
2446 .try_recover()
2447 .unwrap()),
2448 (recovered_block_range, |block: &SealedBlock<Block>| block
2449 .clone()
2450 .try_recover()
2451 .unwrap()),
2452 (transactions_by_block_range, |block: &SealedBlock<Block>| block
2453 .body()
2454 .transactions
2455 .clone()),
2456 ]);
2457
2458 Ok(())
2459 }
2460
2461 macro_rules! call_method {
2463 ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2464 let result = $provider.$method($($args),*)?;
2465 assert_eq!(
2466 result,
2467 $expected_item,
2468 "{}: item does not match the expected item for arguments {:?}",
2469 stringify!($method),
2470 ($($args),*)
2471 );
2472 }};
2473
2474 (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2476 let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2477 call_method!($provider, $method, (arg), expected_item);
2478 }};
2479
2480 (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2482 let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2483 call_method!($provider, $method, (arg1, arg2), expected_item);
2484 }};
2485 }
2486
2487 macro_rules! test_non_range {
2492 ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2493
2494 let extra_blocks = [$(stringify!($arg_count)),*].len();
2497
2498 let mut rng = generators::rng();
2499 let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2500 &mut rng,
2501 TEST_BLOCKS_COUNT,
2502 TEST_BLOCKS_COUNT + extra_blocks,
2503 BlockRangeParams {
2504 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2505 ..Default::default()
2506 },
2507 )?;
2508
2509 let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2510
2511 $(
2512 let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2513 let tx_num = |block: &SealedBlock<Block>| {
2514 database_blocks
2515 .iter()
2516 .chain(in_memory_blocks.iter())
2517 .take_while(|b| b.number < block.number)
2518 .map(|b| b.transaction_count())
2519 .sum::<usize>() as u64
2520 };
2521
2522 {
2524 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2526
2527 call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2528
2529 database_blocks.push(in_memory_blocks.pop_front().unwrap());
2531 }
2532
2533 let tx_num = |block: &SealedBlock<Block>| {
2535 database_blocks
2536 .iter()
2537 .chain(in_memory_blocks.iter())
2538 .take_while(|b| b.number < block.number)
2539 .map(|b| b.transaction_count())
2540 .sum::<usize>() as u64
2541 };
2542
2543 {
2545 call_method!($arg_count, provider, $method, |_,_,_,_| ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2546 }
2547
2548 {
2550 let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2551
2552 let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2553 call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2554
2555 call_method!($arg_count, provider.database, $method, |_,_,_,_| (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2557 }
2558 )*
2559 }};
2560}
2561
2562 #[test]
2563 fn test_non_range_methods() -> eyre::Result<()> {
2564 let test_tx_index = 0;
2565
2566 test_non_range!([
2567 (
2568 ONE,
2569 header,
2570 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2571 block.hash(),
2572 Some(block.header().clone())
2573 ),
2574 B256::random()
2575 ),
2576 (
2577 ONE,
2578 header_by_number,
2579 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2580 block.number,
2581 Some(block.header().clone())
2582 ),
2583 u64::MAX
2584 ),
2585 (
2586 ONE,
2587 sealed_header,
2588 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2589 block.number,
2590 Some(block.clone_sealed_header())
2591 ),
2592 u64::MAX
2593 ),
2594 (
2595 ONE,
2596 block_hash,
2597 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2598 block.number,
2599 Some(block.hash())
2600 ),
2601 u64::MAX
2602 ),
2603 (
2604 ONE,
2605 block_number,
2606 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2607 block.hash(),
2608 Some(block.number)
2609 ),
2610 B256::random()
2611 ),
2612 (
2613 ONE,
2614 block,
2615 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2616 BlockHashOrNumber::Hash(block.hash()),
2617 Some(block.clone().into_block())
2618 ),
2619 BlockHashOrNumber::Hash(B256::random())
2620 ),
2621 (
2622 ONE,
2623 block,
2624 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2625 BlockHashOrNumber::Number(block.number),
2626 Some(block.clone().into_block())
2627 ),
2628 BlockHashOrNumber::Number(u64::MAX)
2629 ),
2630 (
2631 ONE,
2632 block_body_indices,
2633 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2634 block.number,
2635 Some(StoredBlockBodyIndices {
2636 first_tx_num: tx_num,
2637 tx_count: block.transaction_count() as u64
2638 })
2639 ),
2640 u64::MAX
2641 ),
2642 (
2643 TWO,
2644 recovered_block,
2645 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2646 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2647 block.clone().try_recover().ok()
2648 ),
2649 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2650 ),
2651 (
2652 TWO,
2653 recovered_block,
2654 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2655 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2656 block.clone().try_recover().ok()
2657 ),
2658 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2659 ),
2660 (
2661 TWO,
2662 sealed_block_with_senders,
2663 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2664 (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2665 block.clone().try_recover().ok()
2666 ),
2667 (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2668 ),
2669 (
2670 TWO,
2671 sealed_block_with_senders,
2672 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2673 (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2674 block.clone().try_recover().ok()
2675 ),
2676 (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2677 ),
2678 (
2679 ONE,
2680 transaction_id,
2681 |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2682 tx_hash,
2683 Some(tx_num)
2684 ),
2685 B256::random()
2686 ),
2687 (
2688 ONE,
2689 transaction_by_id,
2690 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2691 tx_num,
2692 Some(block.body().transactions[test_tx_index].clone())
2693 ),
2694 u64::MAX
2695 ),
2696 (
2697 ONE,
2698 transaction_by_id_unhashed,
2699 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2700 tx_num,
2701 Some(block.body().transactions[test_tx_index].clone())
2702 ),
2703 u64::MAX
2704 ),
2705 (
2706 ONE,
2707 transaction_by_hash,
2708 |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2709 tx_hash,
2710 Some(block.body().transactions[test_tx_index].clone())
2711 ),
2712 B256::random()
2713 ),
2714 (
2715 ONE,
2716 block_by_transaction_id,
2717 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2718 tx_num,
2719 Some(block.number)
2720 ),
2721 u64::MAX
2722 ),
2723 (
2724 ONE,
2725 transactions_by_block,
2726 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2727 BlockHashOrNumber::Number(block.number),
2728 Some(block.body().transactions.clone())
2729 ),
2730 BlockHashOrNumber::Number(u64::MAX)
2731 ),
2732 (
2733 ONE,
2734 transactions_by_block,
2735 |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2736 BlockHashOrNumber::Hash(block.hash()),
2737 Some(block.body().transactions.clone())
2738 ),
2739 BlockHashOrNumber::Number(u64::MAX)
2740 ),
2741 (
2742 ONE,
2743 transaction_sender,
2744 |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2745 tx_num,
2746 block.body().transactions[test_tx_index].recover_signer().ok()
2747 ),
2748 u64::MAX
2749 ),
2750 (
2751 ONE,
2752 receipt,
2753 |block: &SealedBlock<Block>,
2754 tx_num: TxNumber,
2755 _: B256,
2756 receipts: &Vec<Vec<Receipt>>| (
2757 tx_num,
2758 Some(receipts[block.number as usize][test_tx_index].clone())
2759 ),
2760 u64::MAX
2761 ),
2762 (
2763 ONE,
2764 receipt_by_hash,
2765 |block: &SealedBlock<Block>,
2766 _: TxNumber,
2767 tx_hash: B256,
2768 receipts: &Vec<Vec<Receipt>>| (
2769 tx_hash,
2770 Some(receipts[block.number as usize][test_tx_index].clone())
2771 ),
2772 B256::random()
2773 ),
2774 (
2775 ONE,
2776 receipts_by_block,
2777 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2778 BlockHashOrNumber::Number(block.number),
2779 Some(receipts[block.number as usize].clone())
2780 ),
2781 BlockHashOrNumber::Number(u64::MAX)
2782 ),
2783 (
2784 ONE,
2785 receipts_by_block,
2786 |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2787 BlockHashOrNumber::Hash(block.hash()),
2788 Some(receipts[block.number as usize].clone())
2789 ),
2790 BlockHashOrNumber::Hash(B256::random())
2791 ),
2792 ]);
2794
2795 Ok(())
2796 }
2797
2798 #[test]
2799 fn test_race() -> eyre::Result<()> {
2800 let mut rng = generators::rng();
2801 let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2802 &mut rng,
2803 TEST_BLOCKS_COUNT - 1,
2804 TEST_BLOCKS_COUNT + 1,
2805 BlockRangeParams {
2806 tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2807 ..Default::default()
2808 },
2809 )?;
2810
2811 let old_transaction_hash_fn =
2814 |hash: B256,
2815 canonical_in_memory_state: CanonicalInMemoryState,
2816 factory: ProviderFactory<MockNodeTypesWithDB>| {
2817 assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2818 Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2819 };
2820
2821 let correct_transaction_hash_fn =
2823 |hash: B256,
2824 canonical_in_memory_state: CanonicalInMemoryState,
2825 _factory: ProviderFactory<MockNodeTypesWithDB>| {
2826 if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
2827 return Ok::<_, ProviderError>(Some(tx));
2828 }
2829 panic!("should not be in database");
2830 };
2832
2833 {
2835 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2838 let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
2839
2840 assert!(matches!(
2843 old_transaction_hash_fn(
2844 *to_be_persisted_tx.tx_hash(),
2845 provider.canonical_in_memory_state(),
2846 provider.database.clone()
2847 ),
2848 Ok(None)
2849 ));
2850 }
2851
2852 {
2854 persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
2857 let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
2858
2859 assert_eq!(
2860 correct_transaction_hash_fn(
2861 *to_be_persisted_tx.tx_hash(),
2862 provider.canonical_in_memory_state(),
2863 provider.database
2864 )
2865 .unwrap(),
2866 Some(to_be_persisted_tx)
2867 );
2868 }
2869
2870 Ok(())
2871 }
2872
2873 fn random_account(nonce: u64) -> (Address, Account) {
2874 (Address::random(), Account { nonce, balance: U256::from(nonce), bytecode_hash: None })
2875 }
2876
2877 fn test_provider_factory_with_genesis() -> eyre::Result<ProviderFactory<MockNodeTypesWithDB>> {
2879 let factory = create_test_provider_factory();
2880 let provider_rw = factory.provider_rw()?;
2881 let mut rng = generators::rng();
2882 let genesis =
2883 random_block(&mut rng, 0, BlockParams { tx_count: Some(0), ..Default::default() });
2884 provider_rw
2885 .insert_block(&genesis.try_recover().expect("failed to seal block with senders"))?;
2886 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(0))?;
2887 provider_rw.commit()?;
2888 Ok(factory)
2889 }
2890
2891 #[test]
2892 fn state_range_provider_account_range_is_sorted_and_bounded() -> eyre::Result<()> {
2893 let factory = test_provider_factory_with_genesis()?;
2894 let provider_rw = factory.provider_rw()?;
2895
2896 let accounts: Vec<_> = (0..5u64).map(random_account).collect();
2897 provider_rw.insert_account_for_hashing(
2898 accounts.iter().map(|(address, account)| (*address, Some(*account))),
2899 )?;
2900 provider_rw.commit()?;
2901
2902 let provider = BlockchainProvider::new(factory)?;
2903
2904 let mut expected: Vec<_> =
2905 accounts.iter().map(|(address, account)| (keccak256(address), *account)).collect();
2906 expected.sort_by_key(|(hash, _)| *hash);
2907 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2908
2909 let all = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
2910 assert_eq!(all.end, RangeEnd::Exhausted);
2911 assert_eq!(all.items, expected);
2912
2913 let bounded = state.account_range(B256::ZERO, expected[1].0, 10_000)?;
2916 assert_eq!(bounded.end, RangeEnd::HashLimit);
2917 assert_eq!(bounded.items, expected[..2]);
2918
2919 Ok(())
2920 }
2921
2922 #[test]
2923 fn state_range_provider_account_range_respects_response_bytes() -> eyre::Result<()> {
2924 let factory = test_provider_factory_with_genesis()?;
2925 let provider_rw = factory.provider_rw()?;
2926
2927 let accounts: Vec<_> = (0..5u64).map(random_account).collect();
2928 provider_rw.insert_account_for_hashing(
2929 accounts.iter().map(|(address, account)| (*address, Some(*account))),
2930 )?;
2931 provider_rw.commit()?;
2932
2933 let provider = BlockchainProvider::new(factory)?;
2934 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2935
2936 let partial = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 150)?;
2938 assert_eq!(partial.end, RangeEnd::ByteLimit);
2939 assert_eq!(partial.items.len(), 1);
2940
2941 Ok(())
2942 }
2943
2944 #[test]
2945 fn state_range_provider_storage_range_and_root() -> eyre::Result<()> {
2946 let factory = test_provider_factory_with_genesis()?;
2947 let provider_rw = factory.provider_rw()?;
2948
2949 let (address, account) = random_account(1);
2950 let hashed_address = keccak256(address);
2951 provider_rw.insert_account_for_hashing([(address, Some(account))])?;
2952 let slots = [
2953 StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) },
2954 StorageEntry { key: B256::with_last_byte(2), value: U256::from(20) },
2955 ];
2956 provider_rw.insert_storage_for_hashing([(address, slots)])?;
2957 provider_rw.commit()?;
2958
2959 let provider = BlockchainProvider::new(factory)?;
2960 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
2961
2962 let expected_root = provider.latest()?.storage_root(address, HashedStorage::default())?;
2963 assert_eq!(state.storage_root_by_hash(hashed_address)?, expected_root);
2964
2965 let returned = state
2966 .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
2967 .unwrap();
2968 assert_eq!(returned.end, RangeEnd::Exhausted);
2969 let mut expected: Vec<_> =
2970 slots.iter().map(|entry| (keccak256(entry.key), entry.value)).collect();
2971 expected.sort_by_key(|(hash, _)| *hash);
2972 assert_eq!(returned.items, expected);
2973
2974 let empty_window =
2976 state.storage_range(hashed_address, B256::ZERO, B256::ZERO, 10_000)?.unwrap();
2977 assert_eq!(empty_window.end, RangeEnd::HashLimit);
2978 assert_eq!(empty_window.items, expected[..1]);
2979
2980 assert!(state
2982 .storage_range(B256::repeat_byte(0xee), B256::ZERO, B256::repeat_byte(0xff), 10_000)?
2983 .is_none());
2984
2985 Ok(())
2986 }
2987
2988 #[test]
2989 fn state_range_provider_proofs_start_at_the_real_root() -> eyre::Result<()> {
2990 let factory = test_provider_factory_with_genesis()?;
2991 let provider_rw = factory.provider_rw()?;
2992
2993 let (address, account) = random_account(1);
2994 let hashed_address = keccak256(address);
2995 let hashed_slot = keccak256(B256::with_last_byte(1));
2996 provider_rw.insert_account_for_hashing([(address, Some(account))])?;
2997 provider_rw.insert_storage_for_hashing([(
2998 address,
2999 [StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) }],
3000 )])?;
3001 provider_rw.commit()?;
3002
3003 let provider = BlockchainProvider::new(factory)?;
3004
3005 let state_root = provider.latest()?.state_root(HashedPostState::default())?;
3008 let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3009 let account_proof = state.account_range_proof(&[hashed_address])?;
3010 assert!(!account_proof.is_empty());
3011 assert_eq!(keccak256(&account_proof[0]), state_root);
3012
3013 let storage_root = state.storage_root_by_hash(hashed_address)?;
3014 let storage_proof = state.storage_range_proof(hashed_address, &[hashed_slot])?;
3015 assert!(!storage_proof.is_empty());
3016 assert_eq!(keccak256(&storage_proof[0]), storage_root);
3017
3018 Ok(())
3019 }
3020
3021 #[test]
3022 fn state_range_provider_serves_recent_root_and_rejects_expired_root() -> eyre::Result<()> {
3023 let mut rng = generators::rng();
3024 let factory = create_test_provider_factory();
3025 let provider_rw = factory.provider_rw()?;
3026 let expired_root = B256::repeat_byte(0x11);
3027 let recent_root = B256::repeat_byte(0x22);
3028 let mut parent = B256::ZERO;
3029
3030 for number in 0..=SNAPSHOT_STATE_RETENTION {
3031 let mut block = random_block(
3032 &mut rng,
3033 number,
3034 BlockParams { parent: Some(parent), tx_count: Some(0), ..Default::default() },
3035 )
3036 .unseal();
3037 block.header.state_root = match number {
3038 0 => expired_root,
3039 64 => recent_root,
3040 _ => EMPTY_ROOT_HASH,
3041 };
3042 let block = block.seal_slow();
3043 parent = block.hash();
3044 provider_rw
3045 .insert_block(&block.try_recover().expect("failed to seal block with senders"))?;
3046 }
3047 provider_rw.save_stage_checkpoint(
3048 StageId::Finish,
3049 StageCheckpoint::new(SNAPSHOT_STATE_RETENTION),
3050 )?;
3051 provider_rw.commit()?;
3052
3053 let provider = BlockchainProvider::new(factory)?;
3054 assert!(provider.state_range_provider(recent_root)?.is_some());
3055 assert!(provider.state_range_provider(expired_root)?.is_none());
3056
3057 Ok(())
3058 }
3059
3060 #[test]
3061 fn state_range_provider_serves_persisted_root_with_in_memory_overlay() -> eyre::Result<()> {
3062 let mut rng = generators::rng();
3063 let (provider, _, _, _) = provider_with_random_blocks(
3064 &mut rng,
3065 TEST_BLOCKS_COUNT - 1,
3066 1,
3067 BlockRangeParams::default(),
3068 )?;
3069 assert!(provider.canonical_in_memory_state.head_state().is_some());
3070 let provider_rw = provider.database.provider_rw()?;
3071 provider_rw.save_stage_checkpoint(
3072 StageId::Finish,
3073 StageCheckpoint::new((TEST_BLOCKS_COUNT - 2) as u64),
3074 )?;
3075 provider_rw.commit()?;
3076
3077 assert!(provider.state_range_provider(EMPTY_ROOT_HASH)?.is_some());
3078
3079 Ok(())
3080 }
3081
3082 #[test]
3083 fn state_range_provider_resolves_root_from_in_memory_block() -> eyre::Result<()> {
3084 let mut rng = generators::rng();
3085 let factory = test_provider_factory_with_genesis()?;
3086 let provider = BlockchainProvider::new(factory)?;
3087
3088 let (address, account) = random_account(1);
3089 let hashed_address = keccak256(address);
3090 let mut hashed_state = HashedPostState::default();
3091 hashed_state.accounts.insert(hashed_address, Some(account));
3092
3093 let unique_root = B256::repeat_byte(0x77);
3096 let parent = provider.canonical_in_memory_state.get_canonical_head();
3097 let mut block = random_block(
3098 &mut rng,
3099 parent.number + 1,
3100 BlockParams { parent: Some(parent.hash()), tx_count: Some(0), ..Default::default() },
3101 )
3102 .unseal();
3103 block.header.state_root = unique_root;
3104 let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3105
3106 let trie_data = ComputedTrieData::new(
3107 Arc::new(hashed_state.into_sorted()),
3108 Arc::new(TrieUpdates::default().into_sorted()),
3109 );
3110 let execution_output = BlockExecutionOutput {
3111 result: BlockExecutionResult {
3112 receipts: Default::default(),
3113 requests: Default::default(),
3114 gas_used: 0,
3115 blob_gas_used: 0,
3116 },
3117 state: Default::default(),
3118 };
3119 let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3120 provider.database.overlay_manager().insert_block(executed.clone());
3121 provider
3122 .canonical_in_memory_state
3123 .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3124
3125 let state =
3126 provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3127 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3128 assert_eq!(range.items, vec![(hashed_address, account)]);
3129
3130 Ok(())
3131 }
3132
3133 #[test]
3134 fn state_range_provider_reverts_database_advancement_past_anchor() -> eyre::Result<()> {
3135 let mut rng = generators::rng();
3136 let factory = test_provider_factory_with_genesis()?;
3137 let provider = BlockchainProvider::new(factory)?;
3138 let genesis = provider.canonical_in_memory_state.get_canonical_head();
3139
3140 let (target_address, target_account) = random_account(1);
3142 let target_hashed = keccak256(target_address);
3143 let mut target_state = HashedPostState::default();
3144 target_state.accounts.insert(target_hashed, Some(target_account));
3145
3146 let unique_root = B256::repeat_byte(0x77);
3147 let mut block = random_block(
3148 &mut rng,
3149 genesis.number + 1,
3150 BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3151 )
3152 .unseal();
3153 block.header.state_root = unique_root;
3154 let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3155 let trie_data = ComputedTrieData::new(
3156 Arc::new(target_state.into_sorted()),
3157 Arc::new(TrieUpdates::default().into_sorted()),
3158 );
3159 let execution_output = BlockExecutionOutput {
3160 result: BlockExecutionResult {
3161 receipts: Default::default(),
3162 requests: Default::default(),
3163 gas_used: 0,
3164 blob_gas_used: 0,
3165 },
3166 state: Default::default(),
3167 };
3168 let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3169 provider.database.overlay_manager().insert_block(executed.clone());
3170 provider
3171 .canonical_in_memory_state
3172 .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3173
3174 let (noise_address, noise_account) = random_account(2);
3178 let noise_block = random_block(
3179 &mut rng,
3180 genesis.number + 1,
3181 BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3182 )
3183 .try_recover()
3184 .expect("failed to seal block with senders");
3185 let mut noise_state = HashedPostState::default();
3186 noise_state.accounts.insert(keccak256(noise_address), Some(noise_account));
3187 let provider_rw = provider.database.provider_rw()?;
3188 provider_rw.append_blocks_with_state(
3189 vec![noise_block],
3190 &ExecutionOutcome {
3191 bundle: BundleState::new(
3192 [(noise_address, None, Some(noise_account.into()), Default::default())],
3193 [[(noise_address, Some(None), [])]],
3194 [],
3195 ),
3196 first_block: genesis.number + 1,
3197 ..Default::default()
3198 },
3199 noise_state.into_sorted(),
3200 )?;
3201 provider_rw
3202 .save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(genesis.number + 1))?;
3203 provider_rw.commit()?;
3204
3205 let state =
3208 provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3209 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3210 assert_eq!(range.items, vec![(target_hashed, target_account)]);
3211
3212 Ok(())
3213 }
3214
3215 #[test]
3216 fn historical_state_range_provider_reverts_state_change_past_retained_anchor(
3217 ) -> eyre::Result<()> {
3218 let mut rng = generators::rng();
3219
3220 let (address, account_a) = random_account(1);
3222 let hashed_address = keccak256(address);
3223 let slot_key = B256::with_last_byte(1);
3224 let slot = U256::from_be_bytes(slot_key.0);
3225 let hashed_slot = keccak256(slot_key);
3226 let value_a = U256::from(1);
3227
3228 let factory = test_provider_factory_with_genesis()?;
3229 let provider_rw = factory.provider_rw()?;
3230 provider_rw.insert_account_for_hashing([(address, Some(account_a))])?;
3231 provider_rw.insert_storage_for_hashing([(
3232 address,
3233 [StorageEntry { key: slot_key, value: value_a }],
3234 )])?;
3235 provider_rw.commit()?;
3236 let anchor_root = factory.latest()?.state_root(HashedPostState::default())?;
3237
3238 let genesis_hash = factory.sealed_header(0)?.unwrap().hash();
3239 let mut anchor_block = random_block(
3240 &mut rng,
3241 1,
3242 BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
3243 )
3244 .unseal();
3245 anchor_block.header.state_root = anchor_root;
3246 let anchor_block =
3247 anchor_block.seal_slow().try_recover().expect("failed to seal block with senders");
3248 let anchor_hash = anchor_block.hash();
3249
3250 let provider_rw = factory.provider_rw()?;
3251 provider_rw.insert_block(&anchor_block)?;
3252 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1))?;
3253 provider_rw.commit()?;
3254
3255 let account_b = Account { nonce: 2, balance: U256::from(2), ..account_a };
3257 let value_b = U256::from(2);
3258
3259 let mut storage = HashMap::default();
3260 storage.insert(slot, (value_a, value_b));
3261
3262 let mut state_b = HashedPostState::default();
3263 state_b.accounts.insert(hashed_address, Some(account_b));
3264 state_b.storages.insert(hashed_address, HashedStorage::from_iter([(hashed_slot, value_b)]));
3265
3266 let state_b_root = factory.latest()?.state_root(state_b.clone())?;
3267 let mut later_block = random_block(
3268 &mut rng,
3269 2,
3270 BlockParams { parent: Some(anchor_hash), tx_count: Some(0), ..Default::default() },
3271 )
3272 .unseal();
3273 later_block.header.state_root = state_b_root;
3274 let later_block =
3275 later_block.seal_slow().try_recover().expect("failed to seal block with senders");
3276
3277 let provider_rw = factory.provider_rw()?;
3278 provider_rw.append_blocks_with_state(
3279 vec![later_block],
3280 &ExecutionOutcome {
3281 bundle: BundleState::new(
3282 [(address, Some(account_a.into()), Some(account_b.into()), storage)],
3283 [[(address, Some(Some(account_a.into())), [(slot, value_a)])]],
3284 [],
3285 ),
3286 first_block: 2,
3287 ..Default::default()
3288 },
3289 state_b.into_sorted(),
3290 )?;
3291 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(2))?;
3292 provider_rw.commit()?;
3293
3294 let provider = BlockchainProvider::new(factory)?;
3297 let state =
3298 provider.state_range_provider(anchor_root)?.expect("retained root must resolve");
3299 let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3300 assert_eq!(range.items, vec![(hashed_address, account_a)]);
3301
3302 let storage_range = state
3303 .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3304 .expect("account must have storage");
3305 assert_eq!(storage_range.items, vec![(hashed_slot, value_a)]);
3306
3307 Ok(())
3308 }
3309}