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 revm::database::states::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
1018impl<N: ProviderNodeTypes> ChainSpecProvider for ConsistentProvider<N> {
1019 type ChainSpec = N::ChainSpec;
1020
1021 fn chain_spec(&self) -> Arc<N::ChainSpec> {
1022 ChainSpecProvider::chain_spec(&self.storage_provider)
1023 }
1024}
1025
1026impl<N: ProviderNodeTypes> BlockReaderIdExt for ConsistentProvider<N> {
1027 fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
1028 match id {
1029 BlockId::Number(num) => self.block_by_number_or_tag(num),
1030 BlockId::Hash(hash) => {
1031 if Some(true) == hash.require_canonical {
1036 self.find_block_by_hash(hash.block_hash, BlockSource::Canonical)
1038 } else {
1039 self.block_by_hash(hash.block_hash)
1040 }
1041 }
1042 }
1043 }
1044
1045 fn header_by_number_or_tag(&self, id: BlockNumberOrTag) -> ProviderResult<Option<HeaderTy<N>>> {
1046 Ok(match id {
1047 BlockNumberOrTag::Latest => {
1048 Some(self.canonical_in_memory_state.get_canonical_head().unseal())
1049 }
1050 BlockNumberOrTag::Finalized => {
1051 self.canonical_in_memory_state.get_finalized_header().map(|h| h.unseal())
1052 }
1053 BlockNumberOrTag::Safe => {
1054 self.canonical_in_memory_state.get_safe_header().map(|h| h.unseal())
1055 }
1056 BlockNumberOrTag::Earliest => self.header_by_number(self.earliest_block_number()?)?,
1057 BlockNumberOrTag::Pending => self.canonical_in_memory_state.pending_header(),
1058
1059 BlockNumberOrTag::Number(num) => self.header_by_number(num)?,
1060 })
1061 }
1062
1063 fn sealed_header_by_number_or_tag(
1064 &self,
1065 id: BlockNumberOrTag,
1066 ) -> ProviderResult<Option<SealedHeader<HeaderTy<N>>>> {
1067 match id {
1068 BlockNumberOrTag::Latest => {
1069 Ok(Some(self.canonical_in_memory_state.get_canonical_head()))
1070 }
1071 BlockNumberOrTag::Finalized => {
1072 Ok(self.canonical_in_memory_state.get_finalized_header())
1073 }
1074 BlockNumberOrTag::Safe => Ok(self.canonical_in_memory_state.get_safe_header()),
1075 BlockNumberOrTag::Earliest => self
1076 .header_by_number(self.earliest_block_number()?)?
1077 .map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h)))),
1078 BlockNumberOrTag::Pending => Ok(self.canonical_in_memory_state.pending_sealed_header()),
1079 BlockNumberOrTag::Number(num) => self
1080 .header_by_number(num)?
1081 .map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h)))),
1082 }
1083 }
1084
1085 fn sealed_header_by_id(
1086 &self,
1087 id: BlockId,
1088 ) -> ProviderResult<Option<SealedHeader<HeaderTy<N>>>> {
1089 Ok(match id {
1090 BlockId::Number(num) => self.sealed_header_by_number_or_tag(num)?,
1091 BlockId::Hash(hash) => self
1092 .header(hash.block_hash)?
1093 .map(|header| SealedHeader::new(header, hash.block_hash)),
1094 })
1095 }
1096
1097 fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<HeaderTy<N>>> {
1098 Ok(match id {
1099 BlockId::Number(num) => self.header_by_number_or_tag(num)?,
1100 BlockId::Hash(hash) => self.header(hash.block_hash)?,
1101 })
1102 }
1103}
1104
1105impl<N: ProviderNodeTypes> StorageChangeSetReader for ConsistentProvider<N> {
1106 fn storage_changeset(
1107 &self,
1108 block_number: BlockNumber,
1109 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
1110 if let Some(state) =
1111 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1112 {
1113 let changesets = state
1114 .block()
1115 .execution_output
1116 .state
1117 .reverts
1118 .to_plain_state_reverts()
1119 .storage
1120 .into_iter()
1121 .flatten()
1122 .flat_map(|revert: PlainStorageRevert| {
1123 revert.storage_revert.into_iter().map(move |(key, value)| {
1124 (
1125 BlockNumberAddress((block_number, revert.address)),
1126 StorageEntry { key: key.into(), value: value.to_previous_value() },
1127 )
1128 })
1129 })
1130 .collect();
1131 Ok(changesets)
1132 } else {
1133 let storage_history_exists = self
1137 .storage_provider
1138 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1139 .and_then(|checkpoint| {
1140 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1145 })
1146 .unwrap_or(true);
1147
1148 if !storage_history_exists {
1149 return Err(ProviderError::StateAtBlockPruned(block_number))
1150 }
1151
1152 self.storage_provider.storage_changeset(block_number)
1153 }
1154 }
1155
1156 fn get_storage_before_block(
1157 &self,
1158 block_number: BlockNumber,
1159 address: Address,
1160 storage_key: B256,
1161 ) -> ProviderResult<Option<StorageEntry>> {
1162 if let Some(state) =
1163 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1164 {
1165 let changeset = state
1166 .block_ref()
1167 .execution_output
1168 .state
1169 .reverts
1170 .to_plain_state_reverts()
1171 .storage
1172 .into_iter()
1173 .flatten()
1174 .find_map(|revert: PlainStorageRevert| {
1175 if revert.address != address {
1176 return None
1177 }
1178 revert.storage_revert.into_iter().find_map(|(key, value)| {
1179 let plain_key = B256::from(key);
1180 (plain_key == storage_key).then(|| StorageEntry {
1181 key: plain_key,
1182 value: value.to_previous_value(),
1183 })
1184 })
1185 });
1186 Ok(changeset)
1187 } else {
1188 let storage_history_exists = self
1189 .storage_provider
1190 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1191 .and_then(|checkpoint| {
1192 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1193 })
1194 .unwrap_or(true);
1195
1196 if !storage_history_exists {
1197 return Err(ProviderError::StateAtBlockPruned(block_number))
1198 }
1199
1200 self.storage_provider.get_storage_before_block(block_number, address, storage_key)
1201 }
1202 }
1203
1204 fn storage_changesets_range(
1205 &self,
1206 range: impl RangeBounds<BlockNumber>,
1207 ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
1208 let range = to_range(range);
1209 let mut changesets = Vec::new();
1210 let database_start = range.start;
1211 let mut database_end = range.end;
1212
1213 if let Some(head_block) = &self.head_block {
1214 database_end = head_block.anchor().number;
1215
1216 for state in head_block.chain() {
1217 let block_changesets = state
1218 .block_ref()
1219 .execution_output
1220 .state
1221 .reverts
1222 .to_plain_state_reverts()
1223 .storage
1224 .into_iter()
1225 .flatten()
1226 .flat_map(|revert: PlainStorageRevert| {
1227 revert.storage_revert.into_iter().map(move |(key, value)| {
1228 (
1229 BlockNumberAddress((state.number(), revert.address)),
1230 StorageEntry { key: key.into(), value: value.to_previous_value() },
1231 )
1232 })
1233 });
1234
1235 changesets.extend(block_changesets);
1236 }
1237 }
1238
1239 if database_start < database_end {
1240 let storage_history_exists = self
1241 .storage_provider
1242 .get_prune_checkpoint(PruneSegment::StorageHistory)?
1243 .and_then(|checkpoint| {
1244 checkpoint.block_number.map(|checkpoint| database_start > checkpoint)
1245 })
1246 .unwrap_or(true);
1247
1248 if !storage_history_exists {
1249 return Err(ProviderError::StateAtBlockPruned(database_start))
1250 }
1251
1252 let db_changesets = self
1253 .storage_provider
1254 .storage_changesets_range(database_start..=database_end - 1)?;
1255 changesets.extend(db_changesets);
1256 }
1257
1258 changesets.sort_by_key(|(block_address, _)| block_address.block_number());
1259
1260 Ok(changesets)
1261 }
1262}
1263
1264impl<N: ProviderNodeTypes> ChangeSetReader for ConsistentProvider<N> {
1265 fn account_block_changeset(
1266 &self,
1267 block_number: BlockNumber,
1268 ) -> ProviderResult<Vec<AccountBeforeTx>> {
1269 if let Some(state) =
1270 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1271 {
1272 let changesets = state
1273 .block_ref()
1274 .execution_output
1275 .state
1276 .reverts
1277 .to_plain_state_reverts()
1278 .accounts
1279 .into_iter()
1280 .flatten()
1281 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) })
1282 .collect();
1283 Ok(changesets)
1284 } else {
1285 let account_history_exists = self
1289 .storage_provider
1290 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1291 .and_then(|checkpoint| {
1292 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1297 })
1298 .unwrap_or(true);
1299
1300 if !account_history_exists {
1301 return Err(ProviderError::StateAtBlockPruned(block_number))
1302 }
1303
1304 self.storage_provider.account_block_changeset(block_number)
1305 }
1306 }
1307
1308 fn get_account_before_block(
1309 &self,
1310 block_number: BlockNumber,
1311 address: Address,
1312 ) -> ProviderResult<Option<AccountBeforeTx>> {
1313 if let Some(state) =
1314 self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
1315 {
1316 let changeset = state
1318 .block_ref()
1319 .execution_output
1320 .state
1321 .reverts
1322 .to_plain_state_reverts()
1323 .accounts
1324 .into_iter()
1325 .flatten()
1326 .find(|(addr, _)| addr == &address)
1327 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) });
1328 Ok(changeset)
1329 } else {
1330 let account_history_exists = self
1333 .storage_provider
1334 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1335 .and_then(|checkpoint| {
1336 checkpoint.block_number.map(|checkpoint| block_number > checkpoint)
1341 })
1342 .unwrap_or(true);
1343
1344 if !account_history_exists {
1345 return Err(ProviderError::StateAtBlockPruned(block_number))
1346 }
1347
1348 self.storage_provider.get_account_before_block(block_number, address)
1350 }
1351 }
1352
1353 fn account_changesets_range(
1354 &self,
1355 range: impl core::ops::RangeBounds<BlockNumber>,
1356 ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
1357 let range = to_range(range);
1358 let mut changesets = Vec::new();
1359 let database_start = range.start;
1360 let mut database_end = range.end;
1361
1362 if let Some(head_block) = &self.head_block {
1364 database_end = head_block.anchor().number;
1366
1367 for state in head_block.chain() {
1368 let block_changesets = state
1370 .block_ref()
1371 .execution_output
1372 .state
1373 .reverts
1374 .to_plain_state_reverts()
1375 .accounts
1376 .into_iter()
1377 .flatten()
1378 .map(|(address, info)| AccountBeforeTx { address, info: info.map(Into::into) });
1379
1380 for changeset in block_changesets {
1381 changesets.push((state.number(), changeset));
1382 }
1383 }
1384 }
1385
1386 if database_start < database_end {
1388 let account_history_exists = self
1390 .storage_provider
1391 .get_prune_checkpoint(PruneSegment::AccountHistory)?
1392 .and_then(|checkpoint| {
1393 checkpoint.block_number.map(|checkpoint| database_start > checkpoint)
1394 })
1395 .unwrap_or(true);
1396
1397 if !account_history_exists {
1398 return Err(ProviderError::StateAtBlockPruned(database_start))
1399 }
1400
1401 let db_changesets =
1402 self.storage_provider.account_changesets_range(database_start..database_end)?;
1403 changesets.extend(db_changesets);
1404 }
1405
1406 changesets.sort_by_key(|(block_num, _)| *block_num);
1407
1408 Ok(changesets)
1409 }
1410}
1411
1412#[cfg(test)]
1413#[allow(clippy::clone_on_copy)]
1414mod tests {
1415 use crate::{
1416 providers::blockchain_provider::BlockchainProvider,
1417 test_utils::create_test_provider_factory, BlockWriter,
1418 };
1419 use alloy_eips::BlockHashOrNumber;
1420 use alloy_primitives::B256;
1421 use itertools::Itertools;
1422 use rand::Rng;
1423 use reth_chain_state::{ExecutedBlock, NewCanonicalChain};
1424 use reth_db_api::models::AccountBeforeTx;
1425 use reth_ethereum_primitives::Block;
1426 use reth_execution_types::{BlockExecutionOutput, BlockExecutionResult, ExecutionOutcome};
1427 use reth_primitives_traits::{RecoveredBlock, SealedBlock};
1428 use reth_storage_api::{BlockReader, BlockSource, ChangeSetReader, StateReader};
1429 use reth_testing_utils::generators::{
1430 self, random_block_range, random_changeset_range, random_eoa_accounts, BlockRangeParams,
1431 };
1432 use revm::database::BundleState;
1433 use std::{
1434 ops::{Bound, Range, RangeBounds},
1435 sync::Arc,
1436 };
1437
1438 const TEST_BLOCKS_COUNT: usize = 5;
1439
1440 fn random_blocks(
1441 rng: &mut impl Rng,
1442 database_blocks: usize,
1443 in_memory_blocks: usize,
1444 requests_count: Option<Range<u8>>,
1445 withdrawals_count: Option<Range<u8>>,
1446 tx_count: impl RangeBounds<u8>,
1447 ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1448 let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1449
1450 let tx_start = match tx_count.start_bound() {
1451 Bound::Included(&n) | Bound::Excluded(&n) => n,
1452 Bound::Unbounded => u8::MIN,
1453 };
1454 let tx_end = match tx_count.end_bound() {
1455 Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1456 Bound::Unbounded => u8::MAX,
1457 };
1458
1459 let blocks = random_block_range(
1460 rng,
1461 0..=block_range,
1462 BlockRangeParams {
1463 parent: Some(B256::ZERO),
1464 tx_count: tx_start..tx_end,
1465 requests_count,
1466 withdrawals_count,
1467 },
1468 );
1469 let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1470 (database_blocks.to_vec(), in_memory_blocks.to_vec())
1471 }
1472
1473 #[test]
1474 fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1475 let mut rng = generators::rng();
1477 let factory = create_test_provider_factory();
1478
1479 let blocks = random_block_range(
1481 &mut rng,
1482 0..=10,
1483 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1484 );
1485 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1486
1487 let provider_rw = factory.provider_rw()?;
1489 for block in database_blocks {
1490 provider_rw.insert_block(
1491 &block.clone().try_recover().expect("failed to seal block with senders"),
1492 )?;
1493 }
1494 provider_rw.commit()?;
1495
1496 let provider = BlockchainProvider::new(factory)?;
1498 let consistent_provider = provider.consistent_provider()?;
1499
1500 let first_db_block = database_blocks.first().unwrap();
1502 let first_in_mem_block = in_memory_blocks.first().unwrap();
1503 let last_in_mem_block = in_memory_blocks.last().unwrap();
1504
1505 assert_eq!(
1507 consistent_provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1508 None
1509 );
1510 assert!(consistent_provider
1511 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Any)?
1512 .is_none());
1513 assert_eq!(
1514 consistent_provider
1515 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1516 None
1517 );
1518 assert_eq!(
1520 consistent_provider
1521 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1522 None
1523 );
1524
1525 let in_memory_block_senders =
1527 first_in_mem_block.senders().expect("failed to recover senders");
1528 let chain = NewCanonicalChain::Commit {
1529 new: vec![ExecutedBlock {
1530 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1531 first_in_mem_block.clone(),
1532 in_memory_block_senders,
1533 )),
1534 ..Default::default()
1535 }],
1536 };
1537 consistent_provider.canonical_in_memory_state.update_chain(chain);
1538 let consistent_provider = provider.consistent_provider()?;
1539
1540 assert_eq!(
1542 consistent_provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1543 Some(first_in_mem_block.clone().into_block())
1544 );
1545 let block = consistent_provider
1546 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Any)?
1547 .expect("in-memory block should be found");
1548 assert_eq!(block.sealed_block(), first_in_mem_block);
1549 assert!(block.recovered_block().is_some());
1550
1551 assert_eq!(
1552 consistent_provider
1553 .find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1554 Some(first_in_mem_block.clone().into_block())
1555 );
1556 let block = consistent_provider
1557 .find_sealed_or_recovered_block(first_in_mem_block.hash(), BlockSource::Canonical)?
1558 .expect("canonical in-memory block should be found");
1559 assert_eq!(block.sealed_block(), first_in_mem_block);
1560 assert!(block.recovered_block().is_some());
1561
1562 assert_eq!(
1564 consistent_provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1565 Some(first_db_block.clone().into_block())
1566 );
1567 let block = consistent_provider
1568 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Any)?
1569 .expect("database block should be found");
1570 assert_eq!(block.sealed_block(), first_db_block);
1571 assert!(block.recovered_block().is_none());
1572
1573 assert_eq!(
1574 consistent_provider
1575 .find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1576 Some(first_db_block.clone().into_block())
1577 );
1578 let block = consistent_provider
1579 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Canonical)?
1580 .expect("canonical database block should be found");
1581 assert_eq!(block.sealed_block(), first_db_block);
1582 assert!(block.recovered_block().is_none());
1583
1584 assert_eq!(
1586 consistent_provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?,
1587 None
1588 );
1589 assert!(consistent_provider
1590 .find_sealed_or_recovered_block(first_db_block.hash(), BlockSource::Pending)?
1591 .is_none());
1592
1593 provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1595 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1596 last_in_mem_block.clone(),
1597 Default::default(),
1598 )),
1599 ..Default::default()
1600 });
1601
1602 assert_eq!(
1604 consistent_provider
1605 .find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1606 Some(last_in_mem_block.clone_block())
1607 );
1608 let block = consistent_provider
1609 .find_sealed_or_recovered_block(last_in_mem_block.hash(), BlockSource::Pending)?
1610 .expect("pending block should be found");
1611 assert_eq!(block.sealed_block(), last_in_mem_block);
1612 assert!(block.recovered_block().is_some());
1613
1614 Ok(())
1615 }
1616
1617 #[test]
1618 fn test_block_reader_block() -> eyre::Result<()> {
1619 let mut rng = generators::rng();
1621 let factory = create_test_provider_factory();
1622
1623 let blocks = random_block_range(
1625 &mut rng,
1626 0..=10,
1627 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1628 );
1629 let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1630
1631 let provider_rw = factory.provider_rw()?;
1633 for block in database_blocks {
1634 provider_rw.insert_block(
1635 &block.clone().try_recover().expect("failed to seal block with senders"),
1636 )?;
1637 }
1638 provider_rw.commit()?;
1639
1640 let provider = BlockchainProvider::new(factory)?;
1642 let consistent_provider = provider.consistent_provider()?;
1643
1644 let first_in_mem_block = in_memory_blocks.first().unwrap();
1646 let first_db_block = database_blocks.first().unwrap();
1648
1649 assert_eq!(
1651 consistent_provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1652 None
1653 );
1654 assert_eq!(
1655 consistent_provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1656 None
1657 );
1658
1659 let in_memory_block_senders =
1661 first_in_mem_block.senders().expect("failed to recover senders");
1662 let chain = NewCanonicalChain::Commit {
1663 new: vec![ExecutedBlock {
1664 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1665 first_in_mem_block.clone(),
1666 in_memory_block_senders,
1667 )),
1668 ..Default::default()
1669 }],
1670 };
1671 consistent_provider.canonical_in_memory_state.update_chain(chain);
1672
1673 let consistent_provider = provider.consistent_provider()?;
1674
1675 assert_eq!(
1677 consistent_provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1678 Some(first_in_mem_block.clone().into_block())
1679 );
1680 assert_eq!(
1681 consistent_provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1682 Some(first_in_mem_block.clone().into_block())
1683 );
1684
1685 assert_eq!(
1687 consistent_provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1688 Some(first_db_block.clone().into_block())
1689 );
1690 assert_eq!(
1691 consistent_provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1692 Some(first_db_block.clone().into_block())
1693 );
1694
1695 Ok(())
1696 }
1697
1698 #[test]
1699 fn test_changeset_reader() -> eyre::Result<()> {
1700 let mut rng = generators::rng();
1701
1702 let (database_blocks, in_memory_blocks) =
1703 random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1704
1705 let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1706 let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1707 let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1708
1709 let accounts = random_eoa_accounts(&mut rng, 2);
1710
1711 let (database_changesets, database_state) = random_changeset_range(
1712 &mut rng,
1713 &database_blocks,
1714 accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1715 0..0,
1716 0..0,
1717 );
1718 let (in_memory_changesets, in_memory_state) = random_changeset_range(
1719 &mut rng,
1720 &in_memory_blocks,
1721 database_state.iter().map(|(address, (account, storage))| {
1722 (*address, (account.clone(), storage.clone()))
1723 }),
1724 0..0,
1725 0..0,
1726 );
1727
1728 let factory = create_test_provider_factory();
1729
1730 let provider_rw = factory.provider_rw()?;
1731 provider_rw.append_blocks_with_state(
1732 database_blocks
1733 .into_iter()
1734 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1735 .collect(),
1736 &ExecutionOutcome {
1737 bundle: BundleState::new(
1738 database_state.into_iter().map(|(address, (account, _))| {
1739 (address, None, Some(account.into()), Default::default())
1740 }),
1741 database_changesets.iter().map(|block_changesets| {
1742 block_changesets.iter().map(|(address, account, _)| {
1743 (*address, Some(Some((account.clone()).into())), [])
1744 })
1745 }),
1746 Vec::new(),
1747 ),
1748 first_block: first_database_block,
1749 ..Default::default()
1750 },
1751 Default::default(),
1752 )?;
1753 provider_rw.commit()?;
1754
1755 let provider = BlockchainProvider::new(factory)?;
1756
1757 let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1758 let chain = NewCanonicalChain::Commit {
1759 new: vec![in_memory_blocks
1760 .first()
1761 .map(|block| {
1762 let senders = block.senders().expect("failed to recover senders");
1763 ExecutedBlock {
1764 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1765 block.clone(),
1766 senders,
1767 )),
1768 execution_output: Arc::new(BlockExecutionOutput {
1769 state: BundleState::new(
1770 in_memory_state.into_iter().map(|(address, (account, _))| {
1771 (address, None, Some(account.into()), Default::default())
1772 }),
1773 [in_memory_changesets.iter().map(|(address, account, _)| {
1774 (*address, Some(Some((account.clone()).into())), Vec::new())
1775 })],
1776 [],
1777 ),
1778 result: BlockExecutionResult {
1779 receipts: Default::default(),
1780 requests: Default::default(),
1781 gas_used: 0,
1782 blob_gas_used: 0,
1783 },
1784 }),
1785 ..Default::default()
1786 }
1787 })
1788 .unwrap()],
1789 };
1790 provider.canonical_in_memory_state.update_chain(chain);
1791
1792 let consistent_provider = provider.consistent_provider()?;
1793
1794 assert_eq!(
1795 consistent_provider.account_block_changeset(last_database_block).unwrap(),
1796 database_changesets
1797 .into_iter()
1798 .next_back()
1799 .unwrap()
1800 .into_iter()
1801 .sorted_by_key(|(address, _, _)| *address)
1802 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1803 .collect::<Vec<_>>()
1804 );
1805 assert_eq!(
1806 consistent_provider.account_block_changeset(first_in_memory_block).unwrap(),
1807 in_memory_changesets
1808 .into_iter()
1809 .sorted_by_key(|(address, _, _)| *address)
1810 .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1811 .collect::<Vec<_>>()
1812 );
1813
1814 Ok(())
1815 }
1816 #[test]
1817 fn test_get_state_storage_value_plain_state() -> eyre::Result<()> {
1818 use alloy_primitives::U256;
1819 use reth_db_api::{models::StorageSettings, tables, transaction::DbTxMut};
1820 use reth_primitives_traits::StorageEntry;
1821 use reth_storage_api::StorageSettingsCache;
1822 use std::collections::HashMap;
1823
1824 let address = alloy_primitives::Address::with_last_byte(1);
1825 let account = reth_primitives_traits::Account {
1826 nonce: 1,
1827 balance: U256::from(1000),
1828 ..Default::default()
1829 };
1830 let slot = U256::from(0x42);
1831 let slot_b256 = B256::from(slot);
1832
1833 let mut rng = generators::rng();
1834 let factory = create_test_provider_factory();
1835 factory.set_storage_settings_cache(StorageSettings::v1());
1836
1837 let blocks = random_block_range(
1838 &mut rng,
1839 0..=1,
1840 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1841 );
1842
1843 let provider_rw = factory.provider_rw()?;
1844 provider_rw.append_blocks_with_state(
1845 blocks
1846 .into_iter()
1847 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1848 .collect(),
1849 &ExecutionOutcome {
1850 bundle: BundleState::new(
1851 [(address, None, Some(account.clone().into()), {
1852 let mut s = HashMap::default();
1853 s.insert(slot, (U256::ZERO, U256::from(100)));
1854 s
1855 })],
1856 [
1857 Vec::new(),
1858 vec![(
1859 address,
1860 Some(Some(account.clone().into())),
1861 vec![(slot, U256::ZERO)],
1862 )],
1863 ],
1864 [],
1865 ),
1866 first_block: 0,
1867 ..Default::default()
1868 },
1869 Default::default(),
1870 )?;
1871
1872 provider_rw.tx_ref().put::<tables::PlainStorageState>(
1873 address,
1874 StorageEntry { key: slot_b256, value: U256::from(100) },
1875 )?;
1876 provider_rw.tx_ref().put::<tables::PlainAccountState>(address, account)?;
1877
1878 provider_rw.commit()?;
1879
1880 let provider = BlockchainProvider::new(factory)?;
1881 let outcome = provider.get_state(1)?.expect("should return execution outcome");
1882
1883 let state = &outcome.bundle.state;
1884 let account_state = state.get(&address).expect("should have account in bundle state");
1885 let storage = &account_state.storage;
1886
1887 let storage_slot = storage.get(&slot).expect("should have the slot in storage");
1888
1889 assert_eq!(
1890 storage_slot.present_value,
1891 U256::from(100),
1892 "present_value should be 100 (the actual value in PlainStorageState)"
1893 );
1894
1895 Ok(())
1896 }
1897
1898 #[test]
1899 fn test_storage_changeset_consistent_keys_plain_state() -> eyre::Result<()> {
1900 use alloy_primitives::U256;
1901 use reth_db_api::models::StorageSettings;
1902 use reth_storage_api::{StorageChangeSetReader, StorageSettingsCache};
1903 use std::collections::HashMap;
1904
1905 let mut rng = generators::rng();
1906 let factory = create_test_provider_factory();
1907 factory.set_storage_settings_cache(StorageSettings::v1());
1908
1909 let (database_blocks, in_memory_blocks) = random_blocks(&mut rng, 1, 1, None, None, 0..1);
1910
1911 let address = alloy_primitives::Address::with_last_byte(1);
1912 let account = reth_primitives_traits::Account {
1913 nonce: 1,
1914 balance: U256::from(1000),
1915 ..Default::default()
1916 };
1917 let slot = U256::from(0x42);
1918
1919 let provider_rw = factory.provider_rw()?;
1920 provider_rw.append_blocks_with_state(
1921 database_blocks
1922 .into_iter()
1923 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1924 .collect(),
1925 &ExecutionOutcome {
1926 bundle: BundleState::new(
1927 [(address, None, Some(account.clone().into()), {
1928 let mut s = HashMap::default();
1929 s.insert(slot, (U256::ZERO, U256::from(100)));
1930 s
1931 })],
1932 [[(address, Some(Some(account.clone().into())), vec![(slot, U256::ZERO)])]],
1933 [],
1934 ),
1935 first_block: 0,
1936 ..Default::default()
1937 },
1938 Default::default(),
1939 )?;
1940 provider_rw.commit()?;
1941
1942 let provider = BlockchainProvider::new(factory)?;
1943
1944 let in_mem_block = in_memory_blocks.first().unwrap();
1945 let senders = in_mem_block.senders().expect("failed to recover senders");
1946 let chain = NewCanonicalChain::Commit {
1947 new: vec![ExecutedBlock {
1948 recovered_block: Arc::new(RecoveredBlock::new_sealed(
1949 in_mem_block.clone(),
1950 senders,
1951 )),
1952 execution_output: Arc::new(BlockExecutionOutput {
1953 state: BundleState::new(
1954 [(address, None, Some(account.clone().into()), {
1955 let mut s = HashMap::default();
1956 s.insert(slot, (U256::from(100), U256::from(200)));
1957 s
1958 })],
1959 [[(address, Some(Some(account.into())), vec![(slot, U256::from(100))])]],
1960 [],
1961 ),
1962 result: BlockExecutionResult {
1963 receipts: Default::default(),
1964 requests: Default::default(),
1965 gas_used: 0,
1966 blob_gas_used: 0,
1967 },
1968 }),
1969 ..Default::default()
1970 }],
1971 };
1972 provider.canonical_in_memory_state.update_chain(chain);
1973
1974 let consistent_provider = provider.consistent_provider()?;
1975
1976 let db_changeset = consistent_provider.storage_changeset(0)?;
1977 let mem_changeset = consistent_provider.storage_changeset(1)?;
1978
1979 let slot_b256 = B256::from(slot);
1980
1981 assert_eq!(db_changeset.len(), 1);
1982 assert_eq!(mem_changeset.len(), 1);
1983
1984 let db_key = db_changeset[0].1.key;
1985 let mem_key = mem_changeset[0].1.key;
1986
1987 assert_eq!(db_key, slot_b256, "DB changeset should use plain (unhashed) key");
1988 assert_eq!(mem_key, slot_b256, "In-memory changeset should use plain (unhashed) key");
1989 assert_eq!(
1990 db_key, mem_key,
1991 "DB and in-memory changesets should return the same key format (plain) for the same logical slot"
1992 );
1993
1994 Ok(())
1995 }
1996
1997 #[test]
1998 fn test_storage_changesets_range_consistent_keys_plain_state() -> eyre::Result<()> {
1999 use alloy_primitives::U256;
2000 use reth_db_api::models::StorageSettings;
2001 use reth_storage_api::{StorageChangeSetReader, StorageSettingsCache};
2002 use std::collections::HashMap;
2003
2004 let mut rng = generators::rng();
2005 let factory = create_test_provider_factory();
2006 factory.set_storage_settings_cache(StorageSettings::v1());
2007
2008 let (database_blocks, in_memory_blocks) = random_blocks(&mut rng, 2, 1, None, None, 0..1);
2009
2010 let address = alloy_primitives::Address::with_last_byte(1);
2011 let account = reth_primitives_traits::Account {
2012 nonce: 1,
2013 balance: U256::from(1000),
2014 ..Default::default()
2015 };
2016 let slot = U256::from(0x42);
2017
2018 let provider_rw = factory.provider_rw()?;
2019 provider_rw.append_blocks_with_state(
2020 database_blocks
2021 .into_iter()
2022 .map(|b| b.try_recover().expect("failed to seal block with senders"))
2023 .collect(),
2024 &ExecutionOutcome {
2025 bundle: BundleState::new(
2026 [(address, None, Some(account.clone().into()), {
2027 let mut s = HashMap::default();
2028 s.insert(slot, (U256::ZERO, U256::from(100)));
2029 s
2030 })],
2031 vec![
2032 vec![(
2033 address,
2034 Some(Some(account.clone().into())),
2035 vec![(slot, U256::ZERO)],
2036 )],
2037 vec![],
2038 ],
2039 [],
2040 ),
2041 first_block: 0,
2042 ..Default::default()
2043 },
2044 Default::default(),
2045 )?;
2046 provider_rw.commit()?;
2047
2048 let provider = BlockchainProvider::new(factory)?;
2049
2050 let in_mem_block = in_memory_blocks.first().unwrap();
2051 let senders = in_mem_block.senders().expect("failed to recover senders");
2052 let chain = NewCanonicalChain::Commit {
2053 new: vec![ExecutedBlock {
2054 recovered_block: Arc::new(RecoveredBlock::new_sealed(
2055 in_mem_block.clone(),
2056 senders,
2057 )),
2058 execution_output: Arc::new(BlockExecutionOutput {
2059 state: BundleState::new(
2060 [(address, None, Some(account.clone().into()), {
2061 let mut s = HashMap::default();
2062 s.insert(slot, (U256::from(100), U256::from(200)));
2063 s
2064 })],
2065 [[(address, Some(Some(account.into())), vec![(slot, U256::from(100))])]],
2066 [],
2067 ),
2068 result: BlockExecutionResult {
2069 receipts: Default::default(),
2070 requests: Default::default(),
2071 gas_used: 0,
2072 blob_gas_used: 0,
2073 },
2074 }),
2075 ..Default::default()
2076 }],
2077 };
2078 provider.canonical_in_memory_state.update_chain(chain);
2079
2080 let consistent_provider = provider.consistent_provider()?;
2081
2082 let all_changesets = consistent_provider.storage_changesets_range(0..=2)?;
2083
2084 assert_eq!(all_changesets.len(), 2, "should have one changeset entry per block");
2085
2086 let slot_b256 = B256::from(slot);
2087 let keys: Vec<B256> = all_changesets.iter().map(|(_, entry)| entry.key).collect();
2088
2089 assert_eq!(
2090 keys[0], keys[1],
2091 "same logical slot should produce identical keys whether from DB or memory"
2092 );
2093 assert_eq!(
2094 keys[0], slot_b256,
2095 "keys should be plain/unhashed when use_hashed_state is false"
2096 );
2097
2098 Ok(())
2099 }
2100}