1use super::{DatabaseProviderRO, ProviderFactory, ProviderNodeTypes};
2use crate::{
3 providers::{StaticFileProvider, StaticFileProviderRWRefMut},
4 to_range, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
5 BlockSource, ChainSpecProvider, ChangeSetReader, HeaderProvider, ProviderError,
6 PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader,
7 StaticFileProviderFactory, TransactionVariant, TransactionsProvider,
8};
9use alloy_consensus::{
10 transaction::{TransactionMeta, TxHashRef},
11 BlockHeader,
12};
13use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, HashOrNumber};
14use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256};
15use reth_chain_state::{BlockState, CanonicalInMemoryState};
16use reth_chainspec::ChainInfo;
17use reth_db_api::models::{AccountBeforeTx, BlockNumberAddress, StoredBlockBodyIndices};
18use reth_execution_types::RecoveredBlockAndExecutionOutput;
19use reth_node_types::{BlockTy, HeaderTy, ReceiptTy, TxTy};
20use reth_primitives_traits::{
21 BlockBody, RecoveredBlock, SealedHeader, SealedOrRecoveredBlock, StorageEntry,
22};
23use reth_prune_types::{PruneCheckpoint, PruneSegment};
24use reth_stages_types::{StageCheckpoint, StageId};
25use reth_static_file_types::StaticFileSegment;
26use reth_storage_api::{
27 BlockBodyIndicesProvider, DatabaseProviderFactory, NodePrimitivesProvider,
28 StorageChangeSetReader,
29};
30use reth_storage_errors::provider::ProviderResult;
31use reth_trie::bundle_state::PlainStorageRevert;
32use std::{
33 ops::{Add, Bound, RangeBounds, RangeInclusive, Sub},
34 sync::Arc,
35};
36
37#[derive(Debug)]
44#[doc(hidden)] pub struct ConsistentProvider<N: ProviderNodeTypes> {
46 storage_provider: <ProviderFactory<N> as DatabaseProviderFactory>::Provider,
48 head_block: Option<Arc<BlockState<N::Primitives>>>,
50 canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
52}
53
54impl<N: ProviderNodeTypes> ConsistentProvider<N> {
55 pub fn new(
61 storage_provider_factory: ProviderFactory<N>,
62 state: CanonicalInMemoryState<N::Primitives>,
63 ) -> ProviderResult<Self> {
64 let head_block = state.head_state();
72 let storage_provider = storage_provider_factory.database_provider_ro()?;
73 Ok(Self { storage_provider, head_block, canonical_in_memory_state: state })
74 }
75
76 pub(crate) fn into_database_provider(
78 self,
79 ) -> <ProviderFactory<N> as DatabaseProviderFactory>::Provider {
80 self.storage_provider
81 }
82
83 fn convert_range_bounds<T>(
85 &self,
86 range: impl RangeBounds<T>,
87 end_unbounded: impl FnOnce() -> T,
88 ) -> (T, T)
89 where
90 T: Copy + Add<Output = T> + Sub<Output = T> + From<u8>,
91 {
92 let start = match range.start_bound() {
93 Bound::Included(&n) => n,
94 Bound::Excluded(&n) => n + T::from(1u8),
95 Bound::Unbounded => T::from(0u8),
96 };
97
98 let end = match range.end_bound() {
99 Bound::Included(&n) => n,
100 Bound::Excluded(&n) => n - T::from(1u8),
101 Bound::Unbounded => end_unbounded(),
102 };
103
104 (start, end)
105 }
106
107 fn get_in_memory_or_storage_by_block_range_while<T, F, G, P>(
119 &self,
120 range: impl RangeBounds<BlockNumber>,
121 fetch_db_range: F,
122 map_block_state_item: G,
123 mut predicate: P,
124 ) -> ProviderResult<Vec<T>>
125 where
126 F: FnOnce(
127 &DatabaseProviderRO<N::DB, N>,
128 RangeInclusive<BlockNumber>,
129 &mut P,
130 ) -> ProviderResult<Vec<T>>,
131 G: Fn(&BlockState<N::Primitives>, &mut P) -> Option<T>,
132 P: FnMut(&T) -> bool,
133 {
134 let mut in_memory_chain =
142 self.head_block.as_ref().map(|b| b.chain().collect::<Vec<_>>()).unwrap_or_default();
143 let db_provider = &self.storage_provider;
144
145 let (start, end) = self.convert_range_bounds(range, || {
146 in_memory_chain
148 .first()
149 .map(|b| b.number())
150 .unwrap_or_else(|| db_provider.last_block_number().unwrap_or_default())
151 });
152
153 if start > end {
154 return Ok(vec![])
155 }
156
157 let (in_memory, storage_range) = match in_memory_chain.last().as_ref().map(|b| b.number()) {
162 Some(lowest_memory_block) if lowest_memory_block <= end => {
163 let highest_memory_block =
164 in_memory_chain.first().as_ref().map(|b| b.number()).expect("qed");
165
166 let in_memory_range =
170 lowest_memory_block.max(start)..=end.min(highest_memory_block);
171
172 in_memory_chain.truncate(
175 in_memory_chain
176 .len()
177 .saturating_sub(start.saturating_sub(lowest_memory_block) as usize),
178 );
179
180 let storage_range =
181 (lowest_memory_block > start).then(|| start..=lowest_memory_block - 1);
182
183 (Some((in_memory_chain, in_memory_range)), storage_range)
184 }
185 _ => {
186 drop(in_memory_chain);
188
189 (None, Some(start..=end))
190 }
191 };
192
193 let mut items = Vec::with_capacity((end - start + 1) as usize);
194
195 if let Some(storage_range) = storage_range {
196 let mut db_items = fetch_db_range(db_provider, storage_range.clone(), &mut predicate)?;
197 items.append(&mut db_items);
198
199 if items.len() as u64 != storage_range.end() - storage_range.start() + 1 {
202 return Ok(items)
203 }
204 }
205
206 if let Some((in_memory_chain, in_memory_range)) = in_memory {
207 for (num, block) in in_memory_range.zip(in_memory_chain.into_iter().rev()) {
208 debug_assert!(num == block.number());
209 if let Some(item) = map_block_state_item(block, &mut predicate) {
210 items.push(item);
211 } else {
212 break
213 }
214 }
215 }
216
217 Ok(items)
218 }
219
220 fn get_in_memory_or_storage_by_tx_range<S, M, R>(
226 &self,
227 range: impl RangeBounds<BlockNumber>,
228 fetch_from_db: S,
229 fetch_from_block_state: M,
230 ) -> ProviderResult<Vec<R>>
231 where
232 S: FnOnce(
233 &DatabaseProviderRO<N::DB, N>,
234 RangeInclusive<TxNumber>,
235 ) -> ProviderResult<Vec<R>>,
236 M: Fn(RangeInclusive<usize>, &BlockState<N::Primitives>) -> ProviderResult<Vec<R>>,
237 {
238 let in_mem_chain = self.head_block.iter().flat_map(|b| b.chain()).collect::<Vec<_>>();
239 let provider = &self.storage_provider;
240
241 let last_database_block_number = in_mem_chain
244 .last()
245 .map(|b| Ok(b.anchor().number))
246 .unwrap_or_else(|| provider.last_block_number())?;
247
248 let last_block_body_index = provider
251 .block_body_indices(last_database_block_number)?
252 .ok_or(ProviderError::BlockBodyIndicesNotFound(last_database_block_number))?;
253 let mut in_memory_tx_num = last_block_body_index.next_tx_num();
254
255 let (start, end) = self.convert_range_bounds(range, || {
256 in_mem_chain
257 .iter()
258 .map(|b| b.block_ref().recovered_block().body().transactions().len() as u64)
259 .sum::<u64>() +
260 last_block_body_index.last_tx_num()
261 });
262
263 if start > end {
264 return Ok(vec![])
265 }
266
267 let mut tx_range = start..=end;
268
269 if *tx_range.end() < in_memory_tx_num {
272 return fetch_from_db(provider, tx_range);
273 }
274
275 let mut items = Vec::with_capacity((tx_range.end() - tx_range.start() + 1) as usize);
276
277 if *tx_range.start() < in_memory_tx_num {
279 let db_range = *tx_range.start()..=in_memory_tx_num.saturating_sub(1);
281
282 tx_range = in_memory_tx_num..=*tx_range.end();
284
285 items.extend(fetch_from_db(provider, db_range)?);
286 }
287
288 for block_state in in_mem_chain.iter().rev() {
290 let block_tx_count =
291 block_state.block_ref().recovered_block().body().transactions().len();
292 let remaining = (tx_range.end() - tx_range.start() + 1) as usize;
293
294 if *tx_range.start() >= in_memory_tx_num + block_tx_count as u64 {
297 in_memory_tx_num += block_tx_count as u64;
298 continue
299 }
300
301 let skip = (tx_range.start() - in_memory_tx_num) as usize;
303
304 items.extend(fetch_from_block_state(
305 skip..=skip + (remaining.min(block_tx_count - skip) - 1),
306 block_state,
307 )?);
308
309 in_memory_tx_num += block_tx_count as u64;
310
311 if in_memory_tx_num > *tx_range.end() {
313 break
314 }
315
316 tx_range = in_memory_tx_num..=*tx_range.end();
318 }
319
320 Ok(items)
321 }
322
323 fn get_in_memory_or_storage_by_tx<S, M, R>(
326 &self,
327 id: HashOrNumber,
328 fetch_from_db: S,
329 fetch_from_block_state: M,
330 ) -> ProviderResult<Option<R>>
331 where
332 S: FnOnce(&DatabaseProviderRO<N::DB, N>) -> ProviderResult<Option<R>>,
333 M: Fn(usize, TxNumber, &BlockState<N::Primitives>) -> ProviderResult<Option<R>>,
334 {
335 let in_mem_chain = self.head_block.iter().flat_map(|b| b.chain()).collect::<Vec<_>>();
336 let provider = &self.storage_provider;
337
338 let last_database_block_number = in_mem_chain
341 .last()
342 .map(|b| Ok(b.anchor().number))
343 .unwrap_or_else(|| provider.last_block_number())?;
344
345 let last_block_body_index = provider
348 .block_body_indices(last_database_block_number)?
349 .ok_or(ProviderError::BlockBodyIndicesNotFound(last_database_block_number))?;
350 let mut in_memory_tx_num = last_block_body_index.next_tx_num();
351
352 if let HashOrNumber::Number(id) = id &&
355 id < in_memory_tx_num
356 {
357 return fetch_from_db(provider)
358 }
359
360 for block_state in in_mem_chain.iter().rev() {
362 let executed_block = block_state.block_ref();
363 let block = executed_block.recovered_block();
364
365 for tx_index in 0..block.body().transactions().len() {
366 match id {
367 HashOrNumber::Hash(tx_hash) => {
368 if tx_hash == *block.body().transactions()[tx_index].tx_hash() {
369 return fetch_from_block_state(tx_index, in_memory_tx_num, block_state)
370 }
371 }
372 HashOrNumber::Number(id) => {
373 if id == in_memory_tx_num {
374 return fetch_from_block_state(tx_index, in_memory_tx_num, block_state)
375 }
376 }
377 }
378
379 in_memory_tx_num += 1;
380 }
381 }
382
383 if let HashOrNumber::Hash(_) = id {
385 return fetch_from_db(provider)
386 }
387
388 Ok(None)
389 }
390
391 pub(crate) fn get_in_memory_or_storage_by_block<S, M, R>(
393 &self,
394 id: BlockHashOrNumber,
395 fetch_from_db: S,
396 fetch_from_block_state: M,
397 ) -> ProviderResult<R>
398 where
399 S: FnOnce(&DatabaseProviderRO<N::DB, N>) -> ProviderResult<R>,
400 M: Fn(&BlockState<N::Primitives>) -> ProviderResult<R>,
401 {
402 if let Some(Some(block_state)) = self.head_block.as_ref().map(|b| b.block_on_chain(id)) {
403 return fetch_from_block_state(block_state)
404 }
405 fetch_from_db(&self.storage_provider)
406 }
407}
408
409impl<N: ProviderNodeTypes> NodePrimitivesProvider for ConsistentProvider<N> {
410 type Primitives = N::Primitives;
411}
412
413impl<N: ProviderNodeTypes> StaticFileProviderFactory for ConsistentProvider<N> {
414 fn static_file_provider(&self) -> StaticFileProvider<N::Primitives> {
415 self.storage_provider.static_file_provider()
416 }
417
418 fn get_static_file_writer(
419 &self,
420 block: BlockNumber,
421 segment: StaticFileSegment,
422 ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
423 self.storage_provider.get_static_file_writer(block, segment)
424 }
425}
426
427impl<N: ProviderNodeTypes> HeaderProvider for ConsistentProvider<N> {
428 type Header = HeaderTy<N>;
429
430 fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
431 self.get_in_memory_or_storage_by_block(
432 block_hash.into(),
433 |db_provider| db_provider.header(block_hash),
434 |block_state| Ok(Some(block_state.block_ref().recovered_block().clone_header())),
435 )
436 }
437
438 fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
439 self.get_in_memory_or_storage_by_block(
440 num.into(),
441 |db_provider| db_provider.header_by_number(num),
442 |block_state| Ok(Some(block_state.block_ref().recovered_block().clone_header())),
443 )
444 }
445
446 fn headers_range(
447 &self,
448 range: impl RangeBounds<BlockNumber>,
449 ) -> ProviderResult<Vec<Self::Header>> {
450 self.get_in_memory_or_storage_by_block_range_while(
451 range,
452 |db_provider, range, _| db_provider.headers_range(range),
453 |block_state, _| Some(block_state.block_ref().recovered_block().header().clone()),
454 |_| true,
455 )
456 }
457
458 fn sealed_header(
459 &self,
460 number: BlockNumber,
461 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
462 self.get_in_memory_or_storage_by_block(
463 number.into(),
464 |db_provider| db_provider.sealed_header(number),
465 |block_state| Ok(Some(block_state.block_ref().recovered_block().clone_sealed_header())),
466 )
467 }
468
469 fn sealed_headers_range(
470 &self,
471 range: impl RangeBounds<BlockNumber>,
472 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
473 self.get_in_memory_or_storage_by_block_range_while(
474 range,
475 |db_provider, range, _| db_provider.sealed_headers_range(range),
476 |block_state, _| Some(block_state.block_ref().recovered_block().clone_sealed_header()),
477 |_| true,
478 )
479 }
480
481 fn sealed_headers_while(
482 &self,
483 range: impl RangeBounds<BlockNumber>,
484 predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
485 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
486 self.get_in_memory_or_storage_by_block_range_while(
487 range,
488 |db_provider, range, predicate| db_provider.sealed_headers_while(range, predicate),
489 |block_state, predicate| {
490 let header = block_state.block_ref().recovered_block().sealed_header();
491 predicate(header).then(|| header.clone())
492 },
493 predicate,
494 )
495 }
496}
497
498impl<N: ProviderNodeTypes> BlockHashReader for ConsistentProvider<N> {
499 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
500 self.get_in_memory_or_storage_by_block(
501 number.into(),
502 |db_provider| db_provider.block_hash(number),
503 |block_state| Ok(Some(block_state.hash())),
504 )
505 }
506
507 fn canonical_hashes_range(
508 &self,
509 start: BlockNumber,
510 end: BlockNumber,
511 ) -> ProviderResult<Vec<B256>> {
512 self.get_in_memory_or_storage_by_block_range_while(
513 start..end,
514 |db_provider, inclusive_range, _| {
515 db_provider
516 .canonical_hashes_range(*inclusive_range.start(), *inclusive_range.end() + 1)
517 },
518 |block_state, _| Some(block_state.hash()),
519 |_| true,
520 )
521 }
522}
523
524impl<N: ProviderNodeTypes> BlockNumReader for ConsistentProvider<N> {
525 fn chain_info(&self) -> ProviderResult<ChainInfo> {
526 let best_number = self.best_block_number()?;
527 Ok(ChainInfo { best_hash: self.block_hash(best_number)?.unwrap_or_default(), best_number })
528 }
529
530 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
531 self.head_block.as_ref().map(|b| Ok(b.number())).unwrap_or_else(|| self.last_block_number())
532 }
533
534 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
535 self.storage_provider.last_block_number()
536 }
537
538 fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
539 self.get_in_memory_or_storage_by_block(
540 hash.into(),
541 |db_provider| db_provider.block_number(hash),
542 |block_state| Ok(Some(block_state.number())),
543 )
544 }
545}
546
547impl<N: ProviderNodeTypes> BlockIdReader for ConsistentProvider<N> {
548 fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
549 Ok(self.canonical_in_memory_state.pending_block_num_hash())
550 }
551
552 fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
553 Ok(self.canonical_in_memory_state.get_safe_num_hash())
554 }
555
556 fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
557 Ok(self.canonical_in_memory_state.get_finalized_num_hash())
558 }
559}
560
561impl<N: ProviderNodeTypes> BlockReader for ConsistentProvider<N> {
562 type Block = BlockTy<N>;
563
564 fn find_block_by_hash(
565 &self,
566 hash: B256,
567 source: BlockSource,
568 ) -> ProviderResult<Option<Self::Block>> {
569 if source.is_canonical() &&
570 let Some(block) = self.get_in_memory_or_storage_by_block(
571 hash.into(),
572 |db_provider| db_provider.find_block_by_hash(hash, BlockSource::Canonical),
573 |block_state| Ok(Some(block_state.block_ref().recovered_block().clone_block())),
574 )?
575 {
576 return Ok(Some(block))
577 }
578
579 if source.is_pending() {
580 return Ok(self
581 .canonical_in_memory_state
582 .pending_block()
583 .filter(|b| b.hash() == hash)
584 .map(|b| b.into_block()))
585 }
586
587 Ok(None)
588 }
589
590 fn find_sealed_or_recovered_block(
591 &self,
592 hash: B256,
593 source: BlockSource,
594 ) -> ProviderResult<Option<SealedOrRecoveredBlock<Self::Block>>> {
595 if source.is_canonical() &&
596 let Some(block) = self.get_in_memory_or_storage_by_block(
597 hash.into(),
598 |db_provider| {
599 db_provider.find_sealed_or_recovered_block(hash, BlockSource::Canonical)
600 },
601 |block_state| {
602 Ok(Some(SealedOrRecoveredBlock::recovered_arc(Arc::clone(
603 &block_state.block_ref().recovered_block,
604 ))))
605 },
606 )?
607 {
608 return Ok(Some(block))
609 }
610
611 if source.is_pending() &&
612 let Some(block_state) = self.canonical_in_memory_state.pending_state()
613 {
614 let recovered_block = Arc::clone(&block_state.block_ref().recovered_block);
615 if recovered_block.hash() == hash {
616 return Ok(Some(SealedOrRecoveredBlock::recovered_arc(recovered_block)))
617 }
618 }
619
620 Ok(None)
621 }
622
623 fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
624 self.get_in_memory_or_storage_by_block(
625 id,
626 |db_provider| db_provider.block(id),
627 |block_state| Ok(Some(block_state.block_ref().recovered_block().clone_block())),
628 )
629 }
630
631 fn pending_block(&self) -> ProviderResult<Option<Arc<RecoveredBlock<Self::Block>>>> {
632 Ok(self.canonical_in_memory_state.pending_recovered_block())
633 }
634
635 fn pending_block_and_receipts(
636 &self,
637 ) -> ProviderResult<Option<RecoveredBlockAndExecutionOutput<Self::Block, Self::Receipt>>> {
638 Ok(self.canonical_in_memory_state.pending_block_and_receipts())
639 }
640
641 fn recovered_block(
648 &self,
649 id: BlockHashOrNumber,
650 transaction_kind: TransactionVariant,
651 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
652 self.get_in_memory_or_storage_by_block(
653 id,
654 |db_provider| db_provider.recovered_block(id, transaction_kind),
655 |block_state| Ok(Some(block_state.block().recovered_block().clone())),
656 )
657 }
658
659 fn sealed_block_with_senders(
660 &self,
661 id: BlockHashOrNumber,
662 transaction_kind: TransactionVariant,
663 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
664 self.get_in_memory_or_storage_by_block(
665 id,
666 |db_provider| db_provider.sealed_block_with_senders(id, transaction_kind),
667 |block_state| Ok(Some(block_state.block().recovered_block().clone())),
668 )
669 }
670
671 fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
672 self.get_in_memory_or_storage_by_block_range_while(
673 range,
674 |db_provider, range, _| db_provider.block_range(range),
675 |block_state, _| Some(block_state.block_ref().recovered_block().clone_block()),
676 |_| true,
677 )
678 }
679
680 fn block_with_senders_range(
681 &self,
682 range: RangeInclusive<BlockNumber>,
683 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
684 self.get_in_memory_or_storage_by_block_range_while(
685 range,
686 |db_provider, range, _| db_provider.block_with_senders_range(range),
687 |block_state, _| Some(block_state.block().recovered_block().clone()),
688 |_| true,
689 )
690 }
691
692 fn recovered_block_range(
693 &self,
694 range: RangeInclusive<BlockNumber>,
695 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
696 self.get_in_memory_or_storage_by_block_range_while(
697 range,
698 |db_provider, range, _| db_provider.recovered_block_range(range),
699 |block_state, _| Some(block_state.block().recovered_block().clone()),
700 |_| true,
701 )
702 }
703
704 fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
705 self.get_in_memory_or_storage_by_tx(
706 id.into(),
707 |db_provider| db_provider.block_by_transaction_id(id),
708 |_, _, block_state| Ok(Some(block_state.number())),
709 )
710 }
711}
712
713impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
714 type Transaction = TxTy<N>;
715
716 fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
717 self.get_in_memory_or_storage_by_tx(
718 tx_hash.into(),
719 |db_provider| db_provider.transaction_id(tx_hash),
720 |_, tx_number, _| Ok(Some(tx_number)),
721 )
722 }
723
724 fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
725 self.get_in_memory_or_storage_by_tx(
726 id.into(),
727 |provider| provider.transaction_by_id(id),
728 |tx_index, _, block_state| {
729 Ok(block_state
730 .block_ref()
731 .recovered_block()
732 .body()
733 .transactions()
734 .get(tx_index)
735 .cloned())
736 },
737 )
738 }
739
740 fn transaction_by_id_unhashed(
741 &self,
742 id: TxNumber,
743 ) -> ProviderResult<Option<Self::Transaction>> {
744 self.get_in_memory_or_storage_by_tx(
745 id.into(),
746 |provider| provider.transaction_by_id_unhashed(id),
747 |tx_index, _, block_state| {
748 Ok(block_state
749 .block_ref()
750 .recovered_block()
751 .body()
752 .transactions()
753 .get(tx_index)
754 .cloned())
755 },
756 )
757 }
758
759 fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
760 if let Some(tx) = self.head_block.as_ref().and_then(|b| b.transaction_on_chain(hash)) {
761 return Ok(Some(tx))
762 }
763
764 self.storage_provider.transaction_by_hash(hash)
765 }
766
767 fn transaction_by_hash_with_meta(
768 &self,
769 tx_hash: TxHash,
770 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
771 if let Some((tx, meta)) =
772 self.head_block.as_ref().and_then(|b| b.transaction_meta_on_chain(tx_hash))
773 {
774 return Ok(Some((tx, meta)))
775 }
776
777 self.storage_provider.transaction_by_hash_with_meta(tx_hash)
778 }
779
780 fn transactions_by_block(
781 &self,
782 id: BlockHashOrNumber,
783 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
784 self.get_in_memory_or_storage_by_block(
785 id,
786 |provider| provider.transactions_by_block(id),
787 |block_state| {
788 Ok(Some(block_state.block_ref().recovered_block().body().transactions().to_vec()))
789 },
790 )
791 }
792
793 fn transactions_by_block_range(
794 &self,
795 range: impl RangeBounds<BlockNumber>,
796 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
797 self.get_in_memory_or_storage_by_block_range_while(
798 range,
799 |db_provider, range, _| db_provider.transactions_by_block_range(range),
800 |block_state, _| {
801 Some(block_state.block_ref().recovered_block().body().transactions().to_vec())
802 },
803 |_| true,
804 )
805 }
806
807 fn transactions_by_tx_range(
808 &self,
809 range: impl RangeBounds<TxNumber>,
810 ) -> ProviderResult<Vec<Self::Transaction>> {
811 self.get_in_memory_or_storage_by_tx_range(
812 range,
813 |db_provider, db_range| db_provider.transactions_by_tx_range(db_range),
814 |index_range, block_state| {
815 Ok(block_state.block_ref().recovered_block().body().transactions()[index_range]
816 .to_vec())
817 },
818 )
819 }
820
821 fn senders_by_tx_range(
822 &self,
823 range: impl RangeBounds<TxNumber>,
824 ) -> ProviderResult<Vec<Address>> {
825 self.get_in_memory_or_storage_by_tx_range(
826 range,
827 |db_provider, db_range| db_provider.senders_by_tx_range(db_range),
828 |index_range, block_state| {
829 Ok(block_state.block_ref().recovered_block.senders()[index_range].to_vec())
830 },
831 )
832 }
833
834 fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
835 self.get_in_memory_or_storage_by_tx(
836 id.into(),
837 |provider| provider.transaction_sender(id),
838 |tx_index, _, block_state| {
839 Ok(block_state.block_ref().recovered_block.senders().get(tx_index).copied())
840 },
841 )
842 }
843}
844
845impl<N: ProviderNodeTypes> ReceiptProvider for ConsistentProvider<N> {
846 type Receipt = ReceiptTy<N>;
847
848 fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
849 self.get_in_memory_or_storage_by_tx(
850 id.into(),
851 |provider| provider.receipt(id),
852 |tx_index, _, block_state| {
853 Ok(block_state.executed_block_receipts_ref().get(tx_index).cloned())
854 },
855 )
856 }
857
858 fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
859 for block_state in self.head_block.iter().flat_map(|b| b.chain()) {
860 let executed_block = block_state.block_ref();
861 let block = executed_block.recovered_block();
862 let receipts = block_state.executed_block_receipts_ref();
863
864 debug_assert_eq!(
866 block.body().transactions().len(),
867 receipts.len(),
868 "Mismatch between transaction and receipt count"
869 );
870
871 if let Some(tx_index) =
872 block.body().transactions_iter().position(|tx| *tx.tx_hash() == hash)
873 {
874 return Ok(receipts.get(tx_index).cloned());
876 }
877 }
878
879 self.storage_provider.receipt_by_hash(hash)
880 }
881
882 fn receipts_by_block(
883 &self,
884 block: BlockHashOrNumber,
885 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
886 self.get_in_memory_or_storage_by_block(
887 block,
888 |db_provider| db_provider.receipts_by_block(block),
889 |block_state| Ok(Some(block_state.executed_block_receipts())),
890 )
891 }
892
893 fn receipts_by_tx_range(
894 &self,
895 range: impl RangeBounds<TxNumber>,
896 ) -> ProviderResult<Vec<Self::Receipt>> {
897 self.get_in_memory_or_storage_by_tx_range(
898 range,
899 |db_provider, db_range| db_provider.receipts_by_tx_range(db_range),
900 |index_range, block_state| {
901 Ok(block_state.executed_block_receipts_ref()[index_range].to_vec())
902 },
903 )
904 }
905
906 fn receipts_by_block_range(
907 &self,
908 block_range: RangeInclusive<BlockNumber>,
909 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
910 self.storage_provider.receipts_by_block_range(block_range)
911 }
912}
913
914impl<N: ProviderNodeTypes> ReceiptProviderIdExt for ConsistentProvider<N> {
915 fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
916 match block {
917 BlockId::Hash(rpc_block_hash) => {
918 let mut receipts = self.receipts_by_block(rpc_block_hash.block_hash.into())?;
919 if receipts.is_none() &&
920 !rpc_block_hash.require_canonical.unwrap_or(false) &&
921 let Some(state) = self
922 .head_block
923 .as_ref()
924 .and_then(|b| b.block_on_chain(rpc_block_hash.block_hash.into()))
925 {
926 receipts = Some(state.executed_block_receipts());
927 }
928 Ok(receipts)
929 }
930 BlockId::Number(num_tag) => match num_tag {
931 BlockNumberOrTag::Pending => Ok(self
932 .canonical_in_memory_state
933 .pending_state()
934 .map(|block_state| block_state.executed_block_receipts())),
935 _ => {
936 if let Some(num) = self.convert_block_number(num_tag)? {
937 self.receipts_by_block(num.into())
938 } else {
939 Ok(None)
940 }
941 }
942 },
943 }
944 }
945}
946
947impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for ConsistentProvider<N> {
948 fn block_body_indices(
949 &self,
950 number: BlockNumber,
951 ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
952 self.get_in_memory_or_storage_by_block(
953 number.into(),
954 |db_provider| db_provider.block_body_indices(number),
955 |block_state| {
956 let last_storage_block_number = block_state.anchor().number;
958 let mut stored_indices = self
959 .storage_provider
960 .block_body_indices(last_storage_block_number)?
961 .ok_or(ProviderError::BlockBodyIndicesNotFound(last_storage_block_number))?;
962
963 stored_indices.first_tx_num = stored_indices.next_tx_num();
965 stored_indices.tx_count = 0;
966
967 for state in block_state.chain().collect::<Vec<_>>().into_iter().rev() {
969 let block_tx_count =
970 state.block_ref().recovered_block().body().transactions().len() as u64;
971 if state.block_ref().recovered_block().number() == number {
972 stored_indices.tx_count = block_tx_count;
973 } else {
974 stored_indices.first_tx_num += block_tx_count;
975 }
976 }
977
978 Ok(Some(stored_indices))
979 },
980 )
981 }
982
983 fn block_body_indices_range(
984 &self,
985 range: RangeInclusive<BlockNumber>,
986 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
987 range.map_while(|b| self.block_body_indices(b).transpose()).collect()
988 }
989}
990
991impl<N: ProviderNodeTypes> StageCheckpointReader for ConsistentProvider<N> {
992 fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
993 self.storage_provider.get_stage_checkpoint(id)
994 }
995
996 fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
997 self.storage_provider.get_stage_checkpoint_progress(id)
998 }
999
1000 fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
1001 self.storage_provider.get_all_checkpoints()
1002 }
1003}
1004
1005impl<N: ProviderNodeTypes> PruneCheckpointReader for ConsistentProvider<N> {
1006 fn get_prune_checkpoint(
1007 &self,
1008 segment: PruneSegment,
1009 ) -> ProviderResult<Option<PruneCheckpoint>> {
1010 self.storage_provider.get_prune_checkpoint(segment)
1011 }
1012
1013 fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
1014 self.storage_provider.get_prune_checkpoints()
1015 }
1016
1017 fn get_prune_checkpoints_for_availability(
1018 &self,
1019 ) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
1020 self.storage_provider.get_prune_checkpoints_for_availability()
1021 }
1022}
1023
1024impl<N: ProviderNodeTypes> ChainSpecProvider for ConsistentProvider<N> {
1025 type ChainSpec = N::ChainSpec;
1026
1027 fn chain_spec(&self) -> Arc<N::ChainSpec> {
1028 ChainSpecProvider::chain_spec(&self.storage_provider)
1029 }
1030}
1031
1032impl<N: ProviderNodeTypes> BlockReaderIdExt for ConsistentProvider<N> {
1033 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
1034 match id {
1035 BlockId::Number(num) => self.block_by_number_or_tag(num),
1036 BlockId::Hash(hash) => {
1037 if Some(true) == hash.require_canonical {
1042 self.find_block_by_hash(hash.block_hash, BlockSource::Canonical)
1044 } else {
1045 self.block_by_hash(hash.block_hash)
1046 }
1047 }
1048 }
1049 }
1050
1051 fn header_by_number_or_tag(&self, id: BlockNumberOrTag) -> ProviderResult<Option<HeaderTy<N>>> {
1052 Ok(match id {
1053 BlockNumberOrTag::Latest => {
1054 Some(self.canonical_in_memory_state.get_canonical_head().unseal())
1055 }
1056 BlockNumberOrTag::Finalized => {
1057 self.canonical_in_memory_state.get_finalized_header().map(|h| h.unseal())
1058 }
1059 BlockNumberOrTag::Safe => {
1060 self.canonical_in_memory_state.get_safe_header().map(|h| h.unseal())
1061 }
1062 BlockNumberOrTag::Earliest => self.header_by_number(self.earliest_block_number()?)?,
1063 BlockNumberOrTag::Pending => self.canonical_in_memory_state.pending_header(),
1064
1065 BlockNumberOrTag::Number(num) => self.header_by_number(num)?,
1066 })
1067 }
1068
1069 fn sealed_header_by_number_or_tag(
1070 &self,
1071 id: BlockNumberOrTag,
1072 ) -> ProviderResult<Option<SealedHeader<HeaderTy<N>>>> {
1073 match id {
1074 BlockNumberOrTag::Latest => {
1075 Ok(Some(self.canonical_in_memory_state.get_canonical_head()))
1076 }
1077 BlockNumberOrTag::Finalized => {
1078 Ok(self.canonical_in_memory_state.get_finalized_header())
1079 }
1080 BlockNumberOrTag::Safe => Ok(self.canonical_in_memory_state.get_safe_header()),
1081 BlockNumberOrTag::Earliest => self
1082 .header_by_number(self.earliest_block_number()?)?
1083 .map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h)))),
1084 BlockNumberOrTag::Pending => Ok(self.canonical_in_memory_state.pending_sealed_header()),
1085 BlockNumberOrTag::Number(num) => self
1086 .header_by_number(num)?
1087 .map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h)))),
1088 }
1089 }
1090
1091 fn sealed_header_by_id(
1092 &self,
1093 id: BlockId,
1094 ) -> ProviderResult<Option<SealedHeader<HeaderTy<N>>>> {
1095 Ok(match id {
1096 BlockId::Number(num) => self.sealed_header_by_number_or_tag(num)?,
1097 BlockId::Hash(hash) => self
1098 .header(hash.block_hash)?
1099 .map(|header| SealedHeader::new(header, hash.block_hash)),
1100 })
1101 }
1102
1103 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<HeaderTy<N>>> {
1104 Ok(match id {
1105 BlockId::Number(num) => self.header_by_number_or_tag(num)?,
1106 BlockId::Hash(hash) => self.header(hash.block_hash)?,
1107 })
1108 }
1109}
1110
1111impl<N: ProviderNodeTypes> StorageChangeSetReader for ConsistentProvider<N> {
1112 fn storage_changeset(
1113 &self,
1114 block_number: BlockNumber,
1115 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
1116 if let Some(state) =
1117 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1118 {
1119 let changesets = state
1120 .block()
1121 .execution_output
1122 .state
1123 .reverts
1124 .to_plain_state_reverts()
1125 .storage
1126 .into_iter()
1127 .flatten()
1128 .flat_map(|revert: PlainStorageRevert| {
1129 revert.storage_revert.into_iter().map(move |(key, value)| {
1130 (
1131 BlockNumberAddress((block_number, revert.address)),
1132 StorageEntry { key: key.into(), value: value.to_previous_value() },
1133 )
1134 })
1135 })
1136 .collect();
1137 Ok(changesets)
1138 } else {
1139 let storage_history_exists = self
1143 .storage_provider
1144 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1145 .and_then(|checkpoint| {
1146 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1151 })
1152 .unwrap_or(true);
1153
1154 if !storage_history_exists {
1155 return Err(ProviderError::StateAtBlockPruned(block_number))
1156 }
1157
1158 self.storage_provider.storage_changeset(block_number)
1159 }
1160 }
1161
1162 fn get_storage_before_block(
1163 &self,
1164 block_number: BlockNumber,
1165 address: Address,
1166 storage_key: B256,
1167 ) -> ProviderResult<Option<StorageEntry>> {
1168 if let Some(state) =
1169 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1170 {
1171 let changeset = state
1172 .block_ref()
1173 .execution_output
1174 .state
1175 .reverts
1176 .to_plain_state_reverts()
1177 .storage
1178 .into_iter()
1179 .flatten()
1180 .find_map(|revert: PlainStorageRevert| {
1181 if revert.address != address {
1182 return None
1183 }
1184 revert.storage_revert.into_iter().find_map(|(key, value)| {
1185 let plain_key = B256::from(key);
1186 (plain_key == storage_key).then(|| StorageEntry {
1187 key: plain_key,
1188 value: value.to_previous_value(),
1189 })
1190 })
1191 });
1192 Ok(changeset)
1193 } else {
1194 let storage_history_exists = self
1195 .storage_provider
1196 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1197 .and_then(|checkpoint| {
1198 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1199 })
1200 .unwrap_or(true);
1201
1202 if !storage_history_exists {
1203 return Err(ProviderError::StateAtBlockPruned(block_number))
1204 }
1205
1206 self.storage_provider.get_storage_before_block(block_number, address, storage_key)
1207 }
1208 }
1209
1210 fn storage_changesets_range(
1211 &self,
1212 range: impl RangeBounds<BlockNumber>,
1213 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
1214 let range = to_range(range);
1215 let mut changesets = Vec::new();
1216 let database_start = range.start;
1217 let mut database_end = range.end;
1218
1219 if let Some(head_block) = &self.head_block {
1220 database_end = head_block.anchor().number;
1221
1222 for state in head_block.chain() {
1223 let block_changesets = state
1224 .block_ref()
1225 .execution_output
1226 .state
1227 .reverts
1228 .to_plain_state_reverts()
1229 .storage
1230 .into_iter()
1231 .flatten()
1232 .flat_map(|revert: PlainStorageRevert| {
1233 revert.storage_revert.into_iter().map(move |(key, value)| {
1234 (
1235 BlockNumberAddress((state.number(), revert.address)),
1236 StorageEntry { key: key.into(), value: value.to_previous_value() },
1237 )
1238 })
1239 });
1240
1241 changesets.extend(block_changesets);
1242 }
1243 }
1244
1245 if database_start < database_end {
1246 let storage_history_exists = self
1247 .storage_provider
1248 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1249 .and_then(|checkpoint| {
1250 checkpoint.block_number.map(|checkpoint| database_start > checkpoint)
1251 })
1252 .unwrap_or(true);
1253
1254 if !storage_history_exists {
1255 return Err(ProviderError::StateAtBlockPruned(database_start))
1256 }
1257
1258 let db_changesets = self
1259 .storage_provider
1260 .storage_changesets_range(database_start..=database_end - 1)?;
1261 changesets.extend(db_changesets);
1262 }
1263
1264 changesets.sort_by_key(|(block_address, _)| block_address.block_number());
1265
1266 Ok(changesets)
1267 }
1268}
1269
1270impl<N: ProviderNodeTypes> ChangeSetReader for ConsistentProvider<N> {
1271 fn account_block_changeset(
1272 &self,
1273 block_number: BlockNumber,
1274 ) -> ProviderResult<Vec<AccountBeforeTx>> {
1275 if let Some(state) =
1276 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1277 {
1278 let changesets = state
1279 .block_ref()
1280 .execution_output
1281 .state
1282 .reverts
1283 .to_plain_state_reverts()
1284 .accounts
1285 .into_iter()
1286 .flatten()
1287 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) })
1288 .collect();
1289 Ok(changesets)
1290 } else {
1291 let account_history_exists = self
1295 .storage_provider
1296 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1297 .and_then(|checkpoint| {
1298 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1303 })
1304 .unwrap_or(true);
1305
1306 if !account_history_exists {
1307 return Err(ProviderError::StateAtBlockPruned(block_number))
1308 }
1309
1310 self.storage_provider.account_block_changeset(block_number)
1311 }
1312 }
1313
1314 fn get_account_before_block(
1315 &self,
1316 block_number: BlockNumber,
1317 address: Address,
1318 ) -> ProviderResult<Option<AccountBeforeTx>> {
1319 if let Some(state) =
1320 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1321 {
1322 let changeset = state
1324 .block_ref()
1325 .execution_output
1326 .state
1327 .reverts
1328 .to_plain_state_reverts()
1329 .accounts
1330 .into_iter()
1331 .flatten()
1332 .find(|(addr, _)| addr == &address)
1333 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) });
1334 Ok(changeset)
1335 } else {
1336 let account_history_exists = self
1339 .storage_provider
1340 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1341 .and_then(|checkpoint| {
1342 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1347 })
1348 .unwrap_or(true);
1349
1350 if !account_history_exists {
1351 return Err(ProviderError::StateAtBlockPruned(block_number))
1352 }
1353
1354 self.storage_provider.get_account_before_block(block_number, address)
1356 }
1357 }
1358
1359 fn account_changesets_range(
1360 &self,
1361 range: impl core::ops::RangeBounds<BlockNumber>,
1362 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
1363 let range = to_range(range);
1364 let mut changesets = Vec::new();
1365 let database_start = range.start;
1366 let mut database_end = range.end;
1367
1368 if let Some(head_block) = &self.head_block {
1370 database_end = head_block.anchor().number;
1372
1373 for state in head_block.chain() {
1374 let block_changesets = state
1376 .block_ref()
1377 .execution_output
1378 .state
1379 .reverts
1380 .to_plain_state_reverts()
1381 .accounts
1382 .into_iter()
1383 .flatten()
1384 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) });
1385
1386 for changeset in block_changesets {
1387 changesets.push((state.number(), changeset));
1388 }
1389 }
1390 }
1391
1392 if database_start < database_end {
1394 let account_history_exists = self
1396 .storage_provider
1397 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1398 .and_then(|checkpoint| {
1399 checkpoint.block_number.map(|checkpoint| database_start > checkpoint)
1400 })
1401 .unwrap_or(true);
1402
1403 if !account_history_exists {
1404 return Err(ProviderError::StateAtBlockPruned(database_start))
1405 }
1406
1407 let db_changesets =
1408 self.storage_provider.account_changesets_range(database_start..database_end)?;
1409 changesets.extend(db_changesets);
1410 }
1411
1412 changesets.sort_by_key(|(block_num, _)| *block_num);
1413
1414 Ok(changesets)
1415 }
1416}
1417
1418#[cfg(test)]
1419#[allow(clippy::clone_on_copy)]
1420mod tests {
1421 use crate::{
1422 providers::blockchain_provider::BlockchainProvider,
1423 test_utils::create_test_provider_factory, BlockWriter,
1424 };
1425 use alloy_eips::BlockHashOrNumber;
1426 use alloy_primitives::{B256, U256};
1427 use itertools::Itertools;
1428 use rand::Rng;
1429 use reth_chain_state::{ExecutedBlock, NewCanonicalChain};
1430 use reth_db_api::{
1431 models::{AccountBeforeTx, StorageSettings},
1432 tables,
1433 transaction::DbTxMut,
1434 };
1435 use reth_ethereum_primitives::Block;
1436 use reth_execution_types::{BlockExecutionOutput, BlockExecutionResult, ExecutionOutcome};
1437 use reth_primitives_traits::{RecoveredBlock, SealedBlock, StorageEntry};
1438 use reth_storage_api::{
1439 BlockReader, BlockSource, ChangeSetReader, StateReader, StorageChangeSetReader,
1440 StorageSettingsCache,
1441 };
1442 use reth_testing_utils::generators::{
1443 self, random_block_range, random_changeset_range, random_eoa_accounts, BlockRangeParams,
1444 };
1445 use reth_trie::bundle_state::BundleState;
1446 use std::{
1447 collections::HashMap,
1448 ops::{Bound, Range, RangeBounds},
1449 sync::Arc,
1450 };
1451
1452 const TEST_BLOCKS_COUNT: usize = 5;
1453
1454 fn random_blocks(
1455 rng: &mut impl Rng,
1456 database_blocks: usize,
1457 in_memory_blocks: usize,
1458 requests_count: Option<Range<u8>>,
1459 withdrawals_count: Option<Range<u8>>,
1460 tx_count: impl RangeBounds<u8>,
1461 ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1462 let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1463
1464 let tx_start = match tx_count.start_bound() {
1465 Bound::Included(&n) | Bound::Excluded(&n) => n,
1466 Bound::Unbounded => u8::MIN,
1467 };
1468 let tx_end = match tx_count.end_bound() {
1469 Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1470 Bound::Unbounded => u8::MAX,
1471 };
1472
1473 let blocks = random_block_range(
1474 rng,
1475 0..=block_range,
1476 BlockRangeParams {
1477 parent: Some(B256::ZERO),
1478 tx_count: tx_start..tx_end,
1479 requests_count,
1480 withdrawals_count,
1481 },
1482 );
1483 let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1484 (database_blocks.to_vec(), in_memory_blocks.to_vec())
1485 }
1486
1487 #[test]
1488 fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1489 let mut rng = generators::rng();
1491 let factory = create_test_provider_factory();
1492
1493 let blocks = random_block_range(
1495 &mut rng,
1496 0..=10,
1497 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1498 );
1499 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1500
1501 let provider_rw = factory.provider_rw()?;
1503 for block in database_blocks {
1504 provider_rw.insert_block(
1505 &block.clone().try_recover().expect("failed to seal block with senders"),
1506 )?;
1507 }
1508 provider_rw.commit()?;
1509
1510 let provider = BlockchainProvider::new(factory)?;
1512 let consistent_provider = provider.consistent_provider()?;
1513
1514 let first_db_block = database_blocks.first().unwrap();
1516 let first_in_mem_block = in_memory_blocks.first().unwrap();
1517 let last_in_mem_block = in_memory_blocks.last().unwrap();
1518
1519 assert_eq!(
1521 consistent_provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1522 None
1523 );
1524 assert!(consistent_provider
1525 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Any)?
1526 .is_none());
1527 assert_eq!(
1528 consistent_provider
1529 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1530 None
1531 );
1532 assert_eq!(
1534 consistent_provider
1535 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1536 None
1537 );
1538
1539 let in_memory_block_senders =
1541 first_in_mem_block.senders().expect("failed to recover senders");
1542 let chain = NewCanonicalChain::Commit {
1543 new: vec![ExecutedBlock {
1544 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1545 first_in_mem_block.clone(),
1546 in_memory_block_senders,
1547 )),
1548 ..Default::default()
1549 }],
1550 };
1551 consistent_provider.canonical_in_memory_state.update_chain(chain);
1552 let consistent_provider = provider.consistent_provider()?;
1553
1554 assert_eq!(
1556 consistent_provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1557 Some(first_in_mem_block.clone().into_block())
1558 );
1559 let block = consistent_provider
1560 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Any)?
1561 .expect("in-memory block should be found");
1562 assert_eq!(block.sealed_block(), first_in_mem_block);
1563 assert!(block.recovered_block().is_some());
1564
1565 assert_eq!(
1566 consistent_provider
1567 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1568 Some(first_in_mem_block.clone().into_block())
1569 );
1570 let block = consistent_provider
1571 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Canonical)?
1572 .expect("canonical in-memory block should be found");
1573 assert_eq!(block.sealed_block(), first_in_mem_block);
1574 assert!(block.recovered_block().is_some());
1575
1576 assert_eq!(
1578 consistent_provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1579 Some(first_db_block.clone().into_block())
1580 );
1581 let block = consistent_provider
1582 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Any)?
1583 .expect("database block should be found");
1584 assert_eq!(block.sealed_block(), first_db_block);
1585 assert!(block.recovered_block().is_none());
1586
1587 assert_eq!(
1588 consistent_provider
1589 .find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1590 Some(first_db_block.clone().into_block())
1591 );
1592 let block = consistent_provider
1593 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Canonical)?
1594 .expect("canonical database block should be found");
1595 assert_eq!(block.sealed_block(), first_db_block);
1596 assert!(block.recovered_block().is_none());
1597
1598 assert_eq!(
1600 consistent_provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?,
1601 None
1602 );
1603 assert!(consistent_provider
1604 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Pending)?
1605 .is_none());
1606
1607 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1609 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1610 last_in_mem_block.clone(),
1611 Default::default(),
1612 )),
1613 ..Default::default()
1614 });
1615
1616 assert_eq!(
1618 consistent_provider
1619 .find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1620 Some(last_in_mem_block.clone_block())
1621 );
1622 let block = consistent_provider
1623 .find_sealed_or_recovered_block(last_in_mem_block.hash(), BlockSource::Pending)?
1624 .expect("pending block should be found");
1625 assert_eq!(block.sealed_block(), last_in_mem_block);
1626 assert!(block.recovered_block().is_some());
1627
1628 Ok(())
1629 }
1630
1631 #[test]
1632 fn test_block_reader_block() -> eyre::Result<()> {
1633 let mut rng = generators::rng();
1635 let factory = create_test_provider_factory();
1636
1637 let blocks = random_block_range(
1639 &mut rng,
1640 0..=10,
1641 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1642 );
1643 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1644
1645 let provider_rw = factory.provider_rw()?;
1647 for block in database_blocks {
1648 provider_rw.insert_block(
1649 &block.clone().try_recover().expect("failed to seal block with senders"),
1650 )?;
1651 }
1652 provider_rw.commit()?;
1653
1654 let provider = BlockchainProvider::new(factory)?;
1656 let consistent_provider = provider.consistent_provider()?;
1657
1658 let first_in_mem_block = in_memory_blocks.first().unwrap();
1660 let first_db_block = database_blocks.first().unwrap();
1662
1663 assert_eq!(
1665 consistent_provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1666 None
1667 );
1668 assert_eq!(
1669 consistent_provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1670 None
1671 );
1672
1673 let in_memory_block_senders =
1675 first_in_mem_block.senders().expect("failed to recover senders");
1676 let chain = NewCanonicalChain::Commit {
1677 new: vec![ExecutedBlock {
1678 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1679 first_in_mem_block.clone(),
1680 in_memory_block_senders,
1681 )),
1682 ..Default::default()
1683 }],
1684 };
1685 consistent_provider.canonical_in_memory_state.update_chain(chain);
1686
1687 let consistent_provider = provider.consistent_provider()?;
1688
1689 assert_eq!(
1691 consistent_provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1692 Some(first_in_mem_block.clone().into_block())
1693 );
1694 assert_eq!(
1695 consistent_provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1696 Some(first_in_mem_block.clone().into_block())
1697 );
1698
1699 assert_eq!(
1701 consistent_provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1702 Some(first_db_block.clone().into_block())
1703 );
1704 assert_eq!(
1705 consistent_provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1706 Some(first_db_block.clone().into_block())
1707 );
1708
1709 Ok(())
1710 }
1711
1712 #[test]
1713 fn test_changeset_reader() -> eyre::Result<()> {
1714 let mut rng = generators::rng();
1715
1716 let (database_blocks, in_memory_blocks) =
1717 random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1718
1719 let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1720 let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1721 let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1722
1723 let accounts = random_eoa_accounts(&mut rng, 2);
1724
1725 let (database_changesets, database_state) = random_changeset_range(
1726 &mut rng,
1727 &database_blocks,
1728 accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1729 0..0,
1730 0..0,
1731 );
1732 let (in_memory_changesets, in_memory_state) = random_changeset_range(
1733 &mut rng,
1734 &in_memory_blocks,
1735 database_state.iter().map(|(address, (account, storage))| {
1736 (*address, (account.clone(), storage.clone()))
1737 }),
1738 0..0,
1739 0..0,
1740 );
1741
1742 let factory = create_test_provider_factory();
1743
1744 let provider_rw = factory.provider_rw()?;
1745 provider_rw.append_blocks_with_state(
1746 database_blocks
1747 .into_iter()
1748 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1749 .collect(),
1750 &ExecutionOutcome {
1751 bundle: BundleState::new(
1752 database_state.into_iter().map(|(address, (account, _))| {
1753 (address, None, Some(account.into()), Default::default())
1754 }),
1755 database_changesets.iter().map(|block_changesets| {
1756 block_changesets.iter().map(|(address, account, _)| {
1757 (*address, Some(Some(account.clone().into())), [])
1758 })
1759 }),
1760 Vec::new(),
1761 ),
1762 first_block: first_database_block,
1763 ..Default::default()
1764 },
1765 Default::default(),
1766 )?;
1767 provider_rw.commit()?;
1768
1769 let provider = BlockchainProvider::new(factory)?;
1770
1771 let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1772 let chain = NewCanonicalChain::Commit {
1773 new: vec![in_memory_blocks
1774 .first()
1775 .map(|block| {
1776 let senders = block.senders().expect("failed to recover senders");
1777 ExecutedBlock {
1778 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1779 block.clone(),
1780 senders,
1781 )),
1782 execution_output: Arc::new(BlockExecutionOutput {
1783 state: BundleState::new(
1784 in_memory_state.into_iter().map(|(address, (account, _))| {
1785 (address, None, Some(account.into()), Default::default())
1786 }),
1787 [in_memory_changesets.iter().map(|(address, account, _)| {
1788 (*address, Some(Some(account.clone().into())), Vec::new())
1789 })],
1790 [],
1791 ),
1792 result: BlockExecutionResult {
1793 receipts: Default::default(),
1794 requests: Default::default(),
1795 gas_used: 0,
1796 blob_gas_used: 0,
1797 },
1798 }),
1799 ..Default::default()
1800 }
1801 })
1802 .unwrap()],
1803 };
1804 provider.canonical_in_memory_state.update_chain(chain);
1805
1806 let consistent_provider = provider.consistent_provider()?;
1807
1808 assert_eq!(
1809 consistent_provider.account_block_changeset(last_database_block).unwrap(),
1810 database_changesets
1811 .into_iter()
1812 .next_back()
1813 .unwrap()
1814 .into_iter()
1815 .sorted_by_key(|(address, _, _)| *address)
1816 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1817 .collect::<Vec<_>>()
1818 );
1819 assert_eq!(
1820 consistent_provider.account_block_changeset(first_in_memory_block).unwrap(),
1821 in_memory_changesets
1822 .into_iter()
1823 .sorted_by_key(|(address, _, _)| *address)
1824 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1825 .collect::<Vec<_>>()
1826 );
1827
1828 Ok(())
1829 }
1830 #[test]
1831 fn test_get_state_storage_value_plain_state() -> eyre::Result<()> {
1832 let address = alloy_primitives::Address::with_last_byte(1);
1833 let account = reth_primitives_traits::Account {
1834 nonce: 1,
1835 balance: U256::from(1000),
1836 ..Default::default()
1837 };
1838 let slot = U256::from(0x42);
1839 let slot_b256 = B256::from(slot);
1840
1841 let mut rng = generators::rng();
1842 let factory = create_test_provider_factory();
1843 factory.set_storage_settings_cache(StorageSettings::v1());
1844
1845 let blocks = random_block_range(
1846 &mut rng,
1847 0..=1,
1848 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1849 );
1850
1851 let provider_rw = factory.provider_rw()?;
1852 provider_rw.append_blocks_with_state(
1853 blocks
1854 .into_iter()
1855 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1856 .collect(),
1857 &ExecutionOutcome {
1858 bundle: BundleState::new(
1859 [(address, None, Some(account.clone().into()), {
1860 let mut s = HashMap::default();
1861 s.insert(slot, (U256::ZERO, U256::from(100)));
1862 s
1863 })],
1864 [
1865 Vec::new(),
1866 vec![(
1867 address,
1868 Some(Some(account.clone().into())),
1869 vec![(slot, U256::ZERO)],
1870 )],
1871 ],
1872 [],
1873 ),
1874 first_block: 0,
1875 ..Default::default()
1876 },
1877 Default::default(),
1878 )?;
1879
1880 provider_rw.tx_ref().put::<tables::PlainStorageState>(
1881 address,
1882 StorageEntry { key: slot_b256, value: U256::from(100) },
1883 )?;
1884 provider_rw.tx_ref().put::<tables::PlainAccountState>(address, account)?;
1885
1886 provider_rw.commit()?;
1887
1888 let provider = BlockchainProvider::new(factory)?;
1889 let outcome = provider.get_state(1)?.expect("should return execution outcome");
1890
1891 let state = &outcome.bundle.state;
1892 let account_state = state.get(&address).expect("should have account in bundle state");
1893 let storage = &account_state.storage;
1894
1895 let storage_slot = storage.get(&slot).expect("should have the slot in storage");
1896
1897 assert_eq!(
1898 storage_slot.present_value,
1899 U256::from(100),
1900 "present_value should be 100 (the actual value in PlainStorageState)"
1901 );
1902
1903 Ok(())
1904 }
1905
1906 #[test]
1907 fn test_storage_changeset_consistent_keys_plain_state() -> eyre::Result<()> {
1908 let mut rng = generators::rng();
1909 let factory = create_test_provider_factory();
1910 factory.set_storage_settings_cache(StorageSettings::v1());
1911
1912 let (database_blocks, in_memory_blocks) = random_blocks(&mut rng, 1, 1, None, None, 0..1);
1913
1914 let address = alloy_primitives::Address::with_last_byte(1);
1915 let account = reth_primitives_traits::Account {
1916 nonce: 1,
1917 balance: U256::from(1000),
1918 ..Default::default()
1919 };
1920 let slot = U256::from(0x42);
1921
1922 let provider_rw = factory.provider_rw()?;
1923 provider_rw.append_blocks_with_state(
1924 database_blocks
1925 .into_iter()
1926 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1927 .collect(),
1928 &ExecutionOutcome {
1929 bundle: BundleState::new(
1930 [(address, None, Some(account.clone().into()), {
1931 let mut s = HashMap::default();
1932 s.insert(slot, (U256::ZERO, U256::from(100)));
1933 s
1934 })],
1935 [[(address, Some(Some(account.clone().into())), vec![(slot, U256::ZERO)])]],
1936 [],
1937 ),
1938 first_block: 0,
1939 ..Default::default()
1940 },
1941 Default::default(),
1942 )?;
1943 provider_rw.commit()?;
1944
1945 let provider = BlockchainProvider::new(factory)?;
1946
1947 let in_mem_block = in_memory_blocks.first().unwrap();
1948 let senders = in_mem_block.senders().expect("failed to recover senders");
1949 let chain = NewCanonicalChain::Commit {
1950 new: vec![ExecutedBlock {
1951 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1952 in_mem_block.clone(),
1953 senders,
1954 )),
1955 execution_output: Arc::new(BlockExecutionOutput {
1956 state: BundleState::new(
1957 [(address, None, Some(account.clone().into()), {
1958 let mut s = HashMap::default();
1959 s.insert(slot, (U256::from(100), U256::from(200)));
1960 s
1961 })],
1962 [[(address, Some(Some(account.into())), vec![(slot, U256::from(100))])]],
1963 [],
1964 ),
1965 result: BlockExecutionResult {
1966 receipts: Default::default(),
1967 requests: Default::default(),
1968 gas_used: 0,
1969 blob_gas_used: 0,
1970 },
1971 }),
1972 ..Default::default()
1973 }],
1974 };
1975 provider.canonical_in_memory_state.update_chain(chain);
1976
1977 let consistent_provider = provider.consistent_provider()?;
1978
1979 let db_changeset = consistent_provider.storage_changeset(0)?;
1980 let mem_changeset = consistent_provider.storage_changeset(1)?;
1981
1982 let slot_b256 = B256::from(slot);
1983
1984 assert_eq!(db_changeset.len(), 1);
1985 assert_eq!(mem_changeset.len(), 1);
1986
1987 let db_key = db_changeset[0].1.key;
1988 let mem_key = mem_changeset[0].1.key;
1989
1990 assert_eq!(db_key, slot_b256, "DB changeset should use plain (unhashed) key");
1991 assert_eq!(mem_key, slot_b256, "In-memory changeset should use plain (unhashed) key");
1992 assert_eq!(
1993 db_key, mem_key,
1994 "DB and in-memory changesets should return the same key format (plain) for the same logical slot"
1995 );
1996
1997 Ok(())
1998 }
1999
2000 #[test]
2001 fn test_storage_changesets_range_consistent_keys_plain_state() -> eyre::Result<()> {
2002 let mut rng = generators::rng();
2003 let factory = create_test_provider_factory();
2004 factory.set_storage_settings_cache(StorageSettings::v1());
2005
2006 let (database_blocks, in_memory_blocks) = random_blocks(&mut rng, 2, 1, None, None, 0..1);
2007
2008 let address = alloy_primitives::Address::with_last_byte(1);
2009 let account = reth_primitives_traits::Account {
2010 nonce: 1,
2011 balance: U256::from(1000),
2012 ..Default::default()
2013 };
2014 let slot = U256::from(0x42);
2015
2016 let provider_rw = factory.provider_rw()?;
2017 provider_rw.append_blocks_with_state(
2018 database_blocks
2019 .into_iter()
2020 .map(|b| b.try_recover().expect("failed to seal block with senders"))
2021 .collect(),
2022 &ExecutionOutcome {
2023 bundle: BundleState::new(
2024 [(address, None, Some(account.clone().into()), {
2025 let mut s = HashMap::default();
2026 s.insert(slot, (U256::ZERO, U256::from(100)));
2027 s
2028 })],
2029 vec![
2030 vec![(
2031 address,
2032 Some(Some(account.clone().into())),
2033 vec![(slot, U256::ZERO)],
2034 )],
2035 vec![],
2036 ],
2037 [],
2038 ),
2039 first_block: 0,
2040 ..Default::default()
2041 },
2042 Default::default(),
2043 )?;
2044 provider_rw.commit()?;
2045
2046 let provider = BlockchainProvider::new(factory)?;
2047
2048 let in_mem_block = in_memory_blocks.first().unwrap();
2049 let senders = in_mem_block.senders().expect("failed to recover senders");
2050 let chain = NewCanonicalChain::Commit {
2051 new: vec![ExecutedBlock {
2052 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2053 in_mem_block.clone(),
2054 senders,
2055 )),
2056 execution_output: Arc::new(BlockExecutionOutput {
2057 state: BundleState::new(
2058 [(address, None, Some(account.clone().into()), {
2059 let mut s = HashMap::default();
2060 s.insert(slot, (U256::from(100), U256::from(200)));
2061 s
2062 })],
2063 [[(address, Some(Some(account.into())), vec![(slot, U256::from(100))])]],
2064 [],
2065 ),
2066 result: BlockExecutionResult {
2067 receipts: Default::default(),
2068 requests: Default::default(),
2069 gas_used: 0,
2070 blob_gas_used: 0,
2071 },
2072 }),
2073 ..Default::default()
2074 }],
2075 };
2076 provider.canonical_in_memory_state.update_chain(chain);
2077
2078 let consistent_provider = provider.consistent_provider()?;
2079
2080 let all_changesets = consistent_provider.storage_changesets_range(0..=2)?;
2081
2082 assert_eq!(all_changesets.len(), 2, "should have one changeset entry per block");
2083
2084 let slot_b256 = B256::from(slot);
2085 let keys: Vec<B256> = all_changesets.iter().map(|(_, entry)| entry.key).collect();
2086
2087 assert_eq!(
2088 keys[0], keys[1],
2089 "same logical slot should produce identical keys whether from DB or memory"
2090 );
2091 assert_eq!(
2092 keys[0], slot_b256,
2093 "keys should be plain/unhashed when use_hashed_state is false"
2094 );
2095
2096 Ok(())
2097 }
2098}