1use super::{EthStateCacheConfig, MultiConsumerLruCache};
4use crate::block::CachedTransaction;
5use alloy_consensus::{transaction::TxHashRef, BlockHeader};
6use alloy_eip7928::bal::DecodedBal;
7use alloy_eips::BlockHashOrNumber;
8use alloy_primitives::{Address, Bytes, TxHash, B256};
9use futures::{stream::FuturesOrdered, Stream, StreamExt};
10use reth_chain_state::CanonStateNotification;
11use reth_errors::{ProviderError, ProviderResult};
12use reth_execution_types::Chain;
13use reth_primitives_traits::{Block, BlockBody, InMemorySize, NodePrimitives, RecoveredBlock};
14use reth_revm::{
15 bytecode::Bytecode,
16 primitives::{StorageKey, StorageValue},
17 state::bal::{
18 AccountBal as RevmAccountBal, AccountInfoBal as RevmAccountInfoBal, Bal as RevmBal,
19 BalWrites as RevmBalWrites, StorageBal as RevmStorageBal,
20 },
21};
22use reth_storage_api::{BalProvider, BlockReader, TransactionVariant};
23use reth_tasks::Runtime;
24use schnellru::{ByLength, Limiter, LruMap};
25use std::{
26 future::Future,
27 pin::Pin,
28 sync::Arc,
29 task::{Context, Poll},
30};
31use tokio::sync::{
32 mpsc::{unbounded_channel, UnboundedSender},
33 oneshot, Semaphore,
34};
35use tokio_stream::wrappers::UnboundedReceiverStream;
36
37pub mod config;
38pub mod db;
39pub mod metrics;
40pub mod multi_consumer;
41
42type BlockWithSendersResponseSender<B> =
44 oneshot::Sender<ProviderResult<Option<Arc<RecoveredBlock<B>>>>>;
45
46type ReceiptsResponseSender<R> = oneshot::Sender<ProviderResult<Option<Arc<Vec<R>>>>>;
48
49type CachedBlockResponseSender<B> = oneshot::Sender<Option<Arc<RecoveredBlock<B>>>>;
50
51type CachedBlockAndReceiptsResponseSender<B, R> =
52 oneshot::Sender<(Option<Arc<RecoveredBlock<B>>>, Option<Arc<Vec<R>>>)>;
53
54type HeaderResponseSender<H> = oneshot::Sender<ProviderResult<H>>;
56
57type CachedParentBlocksResponseSender<B> = oneshot::Sender<Vec<Arc<RecoveredBlock<B>>>>;
59
60type TransactionHashResponseSender<B, R> = oneshot::Sender<Option<CachedTransaction<B, R>>>;
62
63type BalResponseSender = oneshot::Sender<ProviderResult<Option<CachedRevmBal>>>;
65
66type BlockLruCache<B, L> =
67 MultiConsumerLruCache<B256, Arc<RecoveredBlock<B>>, L, BlockWithSendersResponseSender<B>>;
68
69type ReceiptsLruCache<R, L> =
70 MultiConsumerLruCache<B256, Arc<Vec<R>>, L, ReceiptsResponseSender<R>>;
71
72type HeaderLruCache<H, L> = MultiConsumerLruCache<B256, H, L, HeaderResponseSender<H>>;
73
74type BalLruCache<L> = MultiConsumerLruCache<B256, CachedRevmBal, L, BalResponseSender>;
75
76#[derive(Debug)]
81pub struct EthStateCache<N: NodePrimitives> {
82 to_service: UnboundedSender<CacheAction<N::Block, N::Receipt>>,
83}
84
85impl<N: NodePrimitives> Clone for EthStateCache<N> {
86 fn clone(&self) -> Self {
87 Self { to_service: self.to_service.clone() }
88 }
89}
90
91impl<N: NodePrimitives> EthStateCache<N> {
92 fn create<Provider>(
94 provider: Provider,
95 action_task_spawner: Runtime,
96 config: EthStateCacheConfig,
97 ) -> (Self, EthStateCacheService<Provider, Runtime>)
98 where
99 Provider: BlockReader<Block = N::Block, Receipt = N::Receipt> + BalProvider,
100 {
101 let EthStateCacheConfig {
102 max_blocks,
103 max_receipts,
104 max_headers,
105 max_bals,
106 max_concurrent_db_requests,
107 max_cached_tx_hashes,
108 } = config;
109 let (to_service, rx) = unbounded_channel();
110
111 let service = EthStateCacheService {
112 provider,
113 full_block_cache: BlockLruCache::new(max_blocks, "blocks"),
114 receipts_cache: ReceiptsLruCache::new(max_receipts, "receipts"),
115 headers_cache: HeaderLruCache::new(max_headers, "headers"),
116 bal_cache: BalLruCache::new(max_bals, "bals"),
117 action_tx: to_service.clone(),
118 action_rx: UnboundedReceiverStream::new(rx),
119 action_task_spawner,
120 rate_limiter: Arc::new(Semaphore::new(max_concurrent_db_requests)),
121 tx_hash_index: LruMap::new(ByLength::new(max_cached_tx_hashes)),
122 };
123 let cache = Self { to_service };
124 (cache, service)
125 }
126
127 pub fn spawn_with<Provider>(
132 provider: Provider,
133 config: EthStateCacheConfig,
134 executor: Runtime,
135 ) -> Self
136 where
137 Provider: BlockReader<Block = N::Block, Receipt = N::Receipt>
138 + BalProvider
139 + Clone
140 + Unpin
141 + 'static,
142 {
143 let (this, service) = Self::create(provider, executor.clone(), config);
144 executor.spawn_critical_task("eth state cache", service);
145 this
146 }
147
148 pub async fn get_recovered_block(
152 &self,
153 block_hash: B256,
154 ) -> ProviderResult<Option<Arc<RecoveredBlock<N::Block>>>> {
155 let (response_tx, rx) = oneshot::channel();
156 let _ = self.to_service.send(CacheAction::GetBlockWithSenders { block_hash, response_tx });
157 rx.await.map_err(|_| CacheServiceUnavailable)?
158 }
159
160 pub async fn get_maybe_block(
162 &self,
163 block_hash: B256,
164 ) -> ProviderResult<Option<Arc<RecoveredBlock<N::Block>>>> {
165 let (response_tx, rx) = oneshot::channel();
166 let _ = self.to_service.send(CacheAction::GetCachedBlock { block_hash, response_tx });
167 rx.await.map_err(|_| CacheServiceUnavailable.into())
168 }
169
170 pub async fn get_receipts(
174 &self,
175 block_hash: B256,
176 ) -> ProviderResult<Option<Arc<Vec<N::Receipt>>>> {
177 let (response_tx, rx) = oneshot::channel();
178 let _ = self.to_service.send(CacheAction::GetReceipts { block_hash, response_tx });
179 rx.await.map_err(|_| CacheServiceUnavailable)?
180 }
181
182 pub async fn get_block_and_receipts(
184 &self,
185 block_hash: B256,
186 ) -> ProviderResult<Option<(Arc<RecoveredBlock<N::Block>>, Arc<Vec<N::Receipt>>)>> {
187 let block = self.get_recovered_block(block_hash);
188 let receipts = self.get_receipts(block_hash);
189
190 let (block, receipts) = futures::try_join!(block, receipts)?;
191
192 Ok(block.zip(receipts))
193 }
194
195 pub async fn get_receipts_and_maybe_block(
197 &self,
198 block_hash: B256,
199 ) -> ProviderResult<Option<(Arc<Vec<N::Receipt>>, Option<Arc<RecoveredBlock<N::Block>>>)>> {
200 let (response_tx, rx) = oneshot::channel();
201 let _ = self.to_service.send(CacheAction::GetCachedBlock { block_hash, response_tx });
202
203 let receipts = self.get_receipts(block_hash);
204
205 let (receipts, block) = futures::join!(receipts, rx);
206
207 let block = block.map_err(|_| CacheServiceUnavailable)?;
208 Ok(receipts?.map(|r| (r, block)))
209 }
210
211 pub async fn maybe_cached_block_and_receipts(
213 &self,
214 block_hash: B256,
215 ) -> ProviderResult<(Option<Arc<RecoveredBlock<N::Block>>>, Option<Arc<Vec<N::Receipt>>>)> {
216 let (response_tx, rx) = oneshot::channel();
217 let _ = self
218 .to_service
219 .send(CacheAction::GetCachedBlockAndReceipts { block_hash, response_tx });
220 rx.await.map_err(|_| CacheServiceUnavailable.into())
221 }
222
223 #[expect(clippy::type_complexity)]
225 pub fn get_receipts_and_maybe_block_stream<'a>(
226 &'a self,
227 hashes: Vec<B256>,
228 ) -> impl Stream<
229 Item = ProviderResult<
230 Option<(Arc<Vec<N::Receipt>>, Option<Arc<RecoveredBlock<N::Block>>>)>,
231 >,
232 > + 'a {
233 let futures = hashes.into_iter().map(move |hash| self.get_receipts_and_maybe_block(hash));
234
235 futures.collect::<FuturesOrdered<_>>()
236 }
237
238 pub async fn get_header(&self, block_hash: B256) -> ProviderResult<N::BlockHeader> {
242 let (response_tx, rx) = oneshot::channel();
243 let _ = self.to_service.send(CacheAction::GetHeader { block_hash, response_tx });
244 rx.await.map_err(|_| CacheServiceUnavailable)?
245 }
246
247 pub async fn get_cached_parent_blocks(
255 &self,
256 block_hash: B256,
257 max_blocks: usize,
258 ) -> Option<Vec<Arc<RecoveredBlock<N::Block>>>> {
259 let (response_tx, rx) = oneshot::channel();
260 let _ = self.to_service.send(CacheAction::GetCachedParentBlocks {
261 block_hash,
262 max_blocks,
263 response_tx,
264 });
265
266 let blocks = rx.await.unwrap_or_default();
267 if blocks.is_empty() {
268 None
269 } else {
270 Some(blocks)
271 }
272 }
273
274 pub async fn get_transaction_by_hash(
279 &self,
280 tx_hash: TxHash,
281 ) -> Option<CachedTransaction<N::Block, N::Receipt>> {
282 let (response_tx, rx) = oneshot::channel();
283 let _ = self.to_service.send(CacheAction::GetTransactionByHash { tx_hash, response_tx });
284 rx.await.ok()?
285 }
286
287 pub async fn get_bal(
291 &self,
292 block_hash: B256,
293 ) -> ProviderResult<Option<Arc<DecodedBal<Arc<RevmBal>>>>> {
294 let (response_tx, rx) = oneshot::channel();
295 let _ = self.to_service.send(CacheAction::GetBal { block_hash, response_tx });
296 rx.await
297 .map_err(|_| CacheServiceUnavailable)?
298 .map(|maybe_bal| maybe_bal.map(|cached| cached.0))
299 }
300}
301#[derive(Debug, thiserror::Error)]
303#[error("cache service task stopped")]
304pub struct CacheServiceUnavailable;
305
306impl From<CacheServiceUnavailable> for ProviderError {
307 fn from(err: CacheServiceUnavailable) -> Self {
308 Self::other(err)
309 }
310}
311
312#[must_use = "Type does nothing unless spawned"]
329pub(crate) struct EthStateCacheService<
330 Provider,
331 Tasks,
332 LimitBlocks = ByLength,
333 LimitReceipts = ByLength,
334 LimitHeaders = ByLength,
335 LimitBals = ByLength,
336> where
337 Provider: BlockReader + BalProvider,
338 LimitBlocks: Limiter<B256, Arc<RecoveredBlock<Provider::Block>>>,
339 LimitReceipts: Limiter<B256, Arc<Vec<Provider::Receipt>>>,
340 LimitHeaders: Limiter<B256, Provider::Header>,
341 LimitBals: Limiter<B256, CachedRevmBal>,
342{
343 provider: Provider,
345 full_block_cache: BlockLruCache<Provider::Block, LimitBlocks>,
347 receipts_cache: ReceiptsLruCache<Provider::Receipt, LimitReceipts>,
349 headers_cache: HeaderLruCache<Provider::Header, LimitHeaders>,
354 bal_cache: BalLruCache<LimitBals>,
356 action_tx: UnboundedSender<CacheAction<Provider::Block, Provider::Receipt>>,
358 action_rx: UnboundedReceiverStream<CacheAction<Provider::Block, Provider::Receipt>>,
360 action_task_spawner: Tasks,
362 rate_limiter: Arc<Semaphore>,
366 tx_hash_index: LruMap<TxHash, (B256, usize), ByLength>,
368}
369
370impl<Provider> EthStateCacheService<Provider, Runtime>
371where
372 Provider: BlockReader + BalProvider + Clone + Unpin + 'static,
373{
374 fn index_block_transactions(&mut self, block: &RecoveredBlock<Provider::Block>) {
376 let block_hash = block.hash();
377 for (tx_idx, tx) in block.body().transactions().iter().enumerate() {
378 self.tx_hash_index.insert(*tx.tx_hash(), (block_hash, tx_idx));
379 }
380 }
381
382 fn remove_block_transactions(&mut self, block: &RecoveredBlock<Provider::Block>) {
384 for tx in block.body().transactions() {
385 self.tx_hash_index.remove(tx.tx_hash());
386 }
387 }
388
389 fn on_new_block(
390 &mut self,
391 block_hash: B256,
392 res: ProviderResult<Option<Arc<RecoveredBlock<Provider::Block>>>>,
393 ) {
394 if let Some(queued) = self.full_block_cache.remove(&block_hash) {
395 for tx in queued {
397 let _ = tx.send(res.clone());
398 }
399 }
400
401 if let Ok(Some(block)) = res {
403 self.full_block_cache.insert(block_hash, block);
404 }
405 }
406
407 fn on_new_receipts(
408 &mut self,
409 block_hash: B256,
410 res: ProviderResult<Option<Arc<Vec<Provider::Receipt>>>>,
411 ) {
412 if let Some(queued) = self.receipts_cache.remove(&block_hash) {
413 for tx in queued {
415 let _ = tx.send(res.clone());
416 }
417 }
418
419 if let Ok(Some(receipts)) = res {
421 self.receipts_cache.insert(block_hash, receipts);
422 }
423 }
424
425 fn on_new_bal(&mut self, block_hash: B256, res: ProviderResult<Option<CachedRevmBal>>) {
426 if let Some(queued) = self.bal_cache.remove(&block_hash) {
427 for tx in queued {
428 let _ = tx.send(res.clone());
429 }
430 }
431
432 if let Ok(Some(bal)) = res {
433 self.bal_cache.insert(block_hash, bal);
434 }
435 }
436
437 fn on_reorg_block(
438 &mut self,
439 block_hash: B256,
440 res: ProviderResult<Option<Arc<RecoveredBlock<Provider::Block>>>>,
441 ) {
442 if let Some(queued) = self.full_block_cache.remove(&block_hash) {
443 for tx in queued {
445 let _ = tx.send(res.clone());
446 }
447 }
448 }
449
450 fn on_reorg_receipts(
451 &mut self,
452 block_hash: B256,
453 res: ProviderResult<Option<Arc<Vec<Provider::Receipt>>>>,
454 ) {
455 if let Some(queued) = self.receipts_cache.remove(&block_hash) {
456 for tx in queued {
458 let _ = tx.send(res.clone());
459 }
460 }
461 }
462
463 fn on_reorg_header(&mut self, block_hash: B256, res: ProviderResult<Provider::Header>) {
464 if let Some(queued) = self.headers_cache.remove(&block_hash) {
465 for tx in queued {
467 let _ = tx.send(res.clone());
468 }
469 }
470 }
471
472 fn on_reorg_bal(&mut self, block_hash: B256, res: ProviderResult<Option<CachedRevmBal>>) {
473 if let Some(queued) = self.bal_cache.remove(&block_hash) {
474 for tx in queued {
475 let _ = tx.send(res.clone());
476 }
477 }
478 }
479
480 fn shrink_queues(&mut self) {
482 let min_capacity = 2;
483 self.full_block_cache.shrink_to(min_capacity);
484 self.receipts_cache.shrink_to(min_capacity);
485 self.headers_cache.shrink_to(min_capacity);
486 self.bal_cache.shrink_to(min_capacity);
487 }
488
489 fn update_cached_metrics(&self) {
490 self.full_block_cache.update_cached_metrics();
491 self.receipts_cache.update_cached_metrics();
492 self.headers_cache.update_cached_metrics();
493 self.bal_cache.update_cached_metrics();
494 }
495}
496
497impl<Provider> Future for EthStateCacheService<Provider, Runtime>
498where
499 Provider: BlockReader + BalProvider + Clone + Unpin + 'static,
500{
501 type Output = ();
502
503 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
504 let this = self.get_mut();
505
506 loop {
507 let Poll::Ready(action) = this.action_rx.poll_next_unpin(cx) else {
508 this.shrink_queues();
510 return Poll::Pending;
511 };
512
513 match action {
514 None => {
515 unreachable!("can't close")
516 }
517 Some(action) => {
518 match action {
519 CacheAction::GetCachedBlock { block_hash, response_tx } => {
520 let _ =
521 response_tx.send(this.full_block_cache.get(&block_hash).cloned());
522 }
523 CacheAction::GetCachedBlockAndReceipts { block_hash, response_tx } => {
524 let block = this.full_block_cache.get(&block_hash).cloned();
525 let receipts = this.receipts_cache.get(&block_hash).cloned();
526 let _ = response_tx.send((block, receipts));
527 }
528 CacheAction::GetBlockWithSenders { block_hash, response_tx } => {
529 if let Some(block) = this.full_block_cache.get(&block_hash).cloned() {
530 let _ = response_tx.send(Ok(Some(block)));
531 continue
532 }
533
534 if this.full_block_cache.queue(block_hash, response_tx) {
536 let provider = this.provider.clone();
537 let action_tx = this.action_tx.clone();
538 let rate_limiter = this.rate_limiter.clone();
539 let mut action_sender =
540 ActionSender::new(CacheKind::Block, block_hash, action_tx);
541 this.action_task_spawner.spawn_blocking_task(async move {
542 let _permit = rate_limiter.acquire().await;
544 let block_sender = provider
547 .sealed_block_with_senders(
548 BlockHashOrNumber::Hash(block_hash),
549 TransactionVariant::WithHash,
550 )
551 .map(|maybe_block| maybe_block.map(Arc::new));
552 action_sender.send_block(block_sender);
553 });
554 }
555 }
556 CacheAction::GetReceipts { block_hash, response_tx } => {
557 if let Some(receipts) = this.receipts_cache.get(&block_hash).cloned() {
559 let _ = response_tx.send(Ok(Some(receipts)));
560 continue
561 }
562
563 if this.receipts_cache.queue(block_hash, response_tx) {
565 let provider = this.provider.clone();
566 let action_tx = this.action_tx.clone();
567 let rate_limiter = this.rate_limiter.clone();
568 let mut action_sender =
569 ActionSender::new(CacheKind::Receipt, block_hash, action_tx);
570 this.action_task_spawner.spawn_blocking_task(async move {
571 let _permit = rate_limiter.acquire().await;
573 let res = provider
574 .receipts_by_block(block_hash.into())
575 .map(|maybe_receipts| maybe_receipts.map(Arc::new));
576
577 action_sender.send_receipts(res);
578 });
579 }
580 }
581 CacheAction::GetHeader { block_hash, response_tx } => {
582 if let Some(header) = this.headers_cache.get(&block_hash).cloned() {
584 let _ = response_tx.send(Ok(header));
585 continue
586 }
587
588 if let Some(block) = this.full_block_cache.get(&block_hash) {
590 let _ = response_tx.send(Ok(block.clone_header()));
591 continue
592 }
593
594 if this.headers_cache.queue(block_hash, response_tx) {
597 let provider = this.provider.clone();
598 let action_tx = this.action_tx.clone();
599 let rate_limiter = this.rate_limiter.clone();
600 let mut action_sender =
601 ActionSender::new(CacheKind::Header, block_hash, action_tx);
602 this.action_task_spawner.spawn_blocking_task(async move {
603 let _permit = rate_limiter.acquire().await;
605 let header = provider.header(block_hash).and_then(|header| {
606 header.ok_or_else(|| {
607 ProviderError::HeaderNotFound(block_hash.into())
608 })
609 });
610 action_sender.send_header(header);
611 });
612 }
613 }
614 CacheAction::GetBal { block_hash, response_tx } => {
615 if let Some(bal) = this.bal_cache.get(&block_hash).cloned() {
616 let _ = response_tx.send(Ok(Some(bal)));
617 continue
618 }
619
620 if this.bal_cache.queue(block_hash, response_tx) {
621 let provider = this.provider.clone();
622 let action_tx = this.action_tx.clone();
623 let rate_limiter = this.rate_limiter.clone();
624 let mut action_sender =
625 ActionSender::new(CacheKind::Bal, block_hash, action_tx);
626 this.action_task_spawner.spawn_blocking_task(async move {
627 let _permit = rate_limiter.acquire().await;
628 let res = provider.get_bal_by_hash(block_hash).and_then(
629 |maybe_bal| {
630 maybe_bal.map(CachedRevmBal::try_from_raw).transpose()
631 },
632 );
633 action_sender.send_bal(res);
634 });
635 }
636 }
637 CacheAction::ReceiptsResult { block_hash, res } => {
638 this.on_new_receipts(block_hash, res);
639 }
640 CacheAction::BalResult { block_hash, res } => {
641 this.on_new_bal(block_hash, res);
642 }
643 CacheAction::BlockWithSendersResult { block_hash, res } => match res {
644 Ok(Some(block_with_senders)) => {
645 this.on_new_block(block_hash, Ok(Some(block_with_senders)));
646 }
647 Ok(None) => {
648 this.on_new_block(block_hash, Ok(None));
649 }
650 Err(e) => {
651 this.on_new_block(block_hash, Err(e));
652 }
653 },
654 CacheAction::HeaderResult { block_hash, res } => {
655 let res = *res;
656 if let Some(queued) = this.headers_cache.remove(&block_hash) {
657 for tx in queued {
659 let _ = tx.send(res.clone());
660 }
661 }
662
663 if let Ok(data) = res {
665 this.headers_cache.insert(block_hash, data);
666 }
667 }
668 CacheAction::CacheNewCanonicalChain { chain_change } => {
669 for block in chain_change.blocks {
670 this.index_block_transactions(&block);
672 this.on_new_block(block.hash(), Ok(Some(block)));
673 }
674
675 for block_receipts in chain_change.receipts {
676 this.on_new_receipts(
677 block_receipts.block_hash,
678 Ok(Some(block_receipts.receipts)),
679 );
680 }
681 }
682 CacheAction::RemoveReorgedChain { chain_change } => {
683 for block in chain_change.blocks {
684 let block_hash = block.hash();
685 let header = block.clone_header();
686 this.remove_block_transactions(&block);
688 this.on_reorg_block(block_hash, Ok(Some(block)));
689 this.on_reorg_header(block_hash, Ok(header));
690 this.on_reorg_bal(block_hash, Ok(None));
691 }
692
693 for block_receipts in chain_change.receipts {
694 this.on_reorg_receipts(
695 block_receipts.block_hash,
696 Ok(Some(block_receipts.receipts)),
697 );
698 }
699 }
700 CacheAction::GetCachedParentBlocks {
701 block_hash,
702 max_blocks,
703 response_tx,
704 } => {
705 let mut blocks = Vec::new();
706 let mut current_hash = block_hash;
707
708 while blocks.len() < max_blocks {
710 if let Some(block) =
711 this.full_block_cache.get(¤t_hash).cloned()
712 {
713 current_hash = block.header().parent_hash();
715 blocks.push(block);
716 } else {
717 break;
719 }
720 }
721
722 let _ = response_tx.send(blocks);
723 }
724 CacheAction::GetTransactionByHash { tx_hash, response_tx } => {
725 let result =
726 this.tx_hash_index.get(&tx_hash).and_then(|(block_hash, idx)| {
727 let block = this.full_block_cache.get(block_hash).cloned()?;
728 let receipts = this.receipts_cache.get(block_hash).cloned();
729 Some(CachedTransaction::new(block, *idx, receipts))
730 });
731 let _ = response_tx.send(result);
732 }
733 };
734 this.update_cached_metrics();
735 }
736 }
737 }
738 }
739}
740
741enum CacheAction<B: Block, R> {
743 GetBlockWithSenders {
744 block_hash: B256,
745 response_tx: BlockWithSendersResponseSender<B>,
746 },
747 GetHeader {
748 block_hash: B256,
749 response_tx: HeaderResponseSender<B::Header>,
750 },
751 GetReceipts {
752 block_hash: B256,
753 response_tx: ReceiptsResponseSender<R>,
754 },
755 GetBal {
756 block_hash: B256,
757 response_tx: BalResponseSender,
758 },
759 GetCachedBlock {
760 block_hash: B256,
761 response_tx: CachedBlockResponseSender<B>,
762 },
763 GetCachedBlockAndReceipts {
764 block_hash: B256,
765 response_tx: CachedBlockAndReceiptsResponseSender<B, R>,
766 },
767 BlockWithSendersResult {
768 block_hash: B256,
769 res: ProviderResult<Option<Arc<RecoveredBlock<B>>>>,
770 },
771 ReceiptsResult {
772 block_hash: B256,
773 res: ProviderResult<Option<Arc<Vec<R>>>>,
774 },
775 HeaderResult {
776 block_hash: B256,
777 res: Box<ProviderResult<B::Header>>,
778 },
779 BalResult {
780 block_hash: B256,
781 res: ProviderResult<Option<CachedRevmBal>>,
782 },
783 CacheNewCanonicalChain {
784 chain_change: ChainChange<B, R>,
785 },
786 RemoveReorgedChain {
787 chain_change: ChainChange<B, R>,
788 },
789 GetCachedParentBlocks {
790 block_hash: B256,
791 max_blocks: usize,
792 response_tx: CachedParentBlocksResponseSender<B>,
793 },
794 GetTransactionByHash {
796 tx_hash: TxHash,
797 response_tx: TransactionHashResponseSender<B, R>,
798 },
799}
800
801struct BlockReceipts<R> {
802 block_hash: B256,
803 receipts: Arc<Vec<R>>,
804}
805
806struct ChainChange<B: Block, R> {
808 blocks: Vec<Arc<RecoveredBlock<B>>>,
809 receipts: Vec<BlockReceipts<R>>,
810}
811
812impl<B: Block, R: Clone> ChainChange<B, R> {
813 fn new<N>(chain: Arc<Chain<N>>) -> Self
814 where
815 N: NodePrimitives<Block = B, Receipt = R>,
816 {
817 let (blocks, receipts): (Vec<_>, Vec<_>) = chain
818 .blocks_and_receipts()
819 .map(|(block, receipts)| {
820 let block_receipts = BlockReceipts {
821 block_hash: block.hash(),
822 receipts: Arc::new(receipts.clone()),
823 };
824 (Arc::clone(block), block_receipts)
825 })
826 .unzip();
827 Self { blocks, receipts }
828 }
829}
830
831#[derive(Copy, Clone, Debug)]
833enum CacheKind {
834 Block,
835 Receipt,
836 Header,
837 Bal,
838}
839
840#[derive(Debug)]
845struct ActionSender<B: Block, R: Send + Sync> {
846 kind: CacheKind,
847 blockhash: B256,
848 tx: Option<UnboundedSender<CacheAction<B, R>>>,
849}
850
851impl<R: Send + Sync, B: Block> ActionSender<B, R> {
852 const fn new(kind: CacheKind, blockhash: B256, tx: UnboundedSender<CacheAction<B, R>>) -> Self {
853 Self { kind, blockhash, tx: Some(tx) }
854 }
855
856 fn send_block(&mut self, block_sender: Result<Option<Arc<RecoveredBlock<B>>>, ProviderError>) {
857 if let Some(tx) = self.tx.take() {
858 let _ = tx.send(CacheAction::BlockWithSendersResult {
859 block_hash: self.blockhash,
860 res: block_sender,
861 });
862 }
863 }
864
865 fn send_receipts(&mut self, receipts: Result<Option<Arc<Vec<R>>>, ProviderError>) {
866 if let Some(tx) = self.tx.take() {
867 let _ =
868 tx.send(CacheAction::ReceiptsResult { block_hash: self.blockhash, res: receipts });
869 }
870 }
871
872 fn send_header(&mut self, header: Result<<B as Block>::Header, ProviderError>) {
873 if let Some(tx) = self.tx.take() {
874 let _ = tx.send(CacheAction::HeaderResult {
875 block_hash: self.blockhash,
876 res: Box::new(header),
877 });
878 }
879 }
880
881 fn send_bal(&mut self, bal: Result<Option<CachedRevmBal>, ProviderError>) {
882 if let Some(tx) = self.tx.take() {
883 let _ = tx.send(CacheAction::BalResult { block_hash: self.blockhash, res: bal });
884 }
885 }
886}
887impl<R: Send + Sync, B: Block> Drop for ActionSender<B, R> {
888 fn drop(&mut self) {
889 if let Some(tx) = self.tx.take() {
890 let msg = match self.kind {
891 CacheKind::Block => CacheAction::BlockWithSendersResult {
892 block_hash: self.blockhash,
893 res: Err(CacheServiceUnavailable.into()),
894 },
895 CacheKind::Receipt => CacheAction::ReceiptsResult {
896 block_hash: self.blockhash,
897 res: Err(CacheServiceUnavailable.into()),
898 },
899 CacheKind::Header => CacheAction::HeaderResult {
900 block_hash: self.blockhash,
901 res: Box::new(Err(CacheServiceUnavailable.into())),
902 },
903 CacheKind::Bal => CacheAction::BalResult {
904 block_hash: self.blockhash,
905 res: Err(CacheServiceUnavailable.into()),
906 },
907 };
908 let _ = tx.send(msg);
909 }
910 }
911}
912
913pub async fn cache_new_blocks_task<St, N: NodePrimitives>(
918 eth_state_cache: EthStateCache<N>,
919 mut events: St,
920) where
921 St: Stream<Item = CanonStateNotification<N>> + Unpin + 'static,
922{
923 while let Some(event) = events.next().await {
924 if let Some(reverted) = event.reverted() {
925 let chain_change = ChainChange::new(reverted);
926
927 let _ =
928 eth_state_cache.to_service.send(CacheAction::RemoveReorgedChain { chain_change });
929 }
930
931 let chain_change = ChainChange::new(event.committed());
932
933 let _ =
934 eth_state_cache.to_service.send(CacheAction::CacheNewCanonicalChain { chain_change });
935 }
936}
937
938#[derive(Clone, Debug)]
940pub(crate) struct CachedRevmBal(Arc<DecodedBal<Arc<RevmBal>>>);
941
942impl CachedRevmBal {
943 #[inline]
945 fn new(bal: DecodedBal<Arc<RevmBal>>) -> Self {
946 Self(Arc::new(bal))
947 }
948
949 fn try_from_raw(raw: Bytes) -> ProviderResult<Self> {
951 DecodedBal::from_rlp_bytes(raw)
952 .map_err(Into::into)
953 .and_then(|decoded| {
954 decoded.try_map(|bal| {
955 RevmBal::try_from(Vec::from(bal)).map(Arc::new).map_err(ProviderError::other)
956 })
957 })
958 .map(Self::new)
959 }
960}
961
962impl InMemorySize for CachedRevmBal {
963 fn size(&self) -> usize {
964 core::mem::size_of::<Self>() + decoded_revm_bal_size(&self.0)
965 }
966}
967
968fn decoded_revm_bal_size(bal: &DecodedBal<Arc<RevmBal>>) -> usize {
969 core::mem::size_of::<DecodedBal<Arc<RevmBal>>>() +
970 bal.as_raw().len() +
971 revm_bal_size(bal.as_bal())
972}
973
974fn revm_bal_size(bal: &Arc<RevmBal>) -> usize {
975 core::mem::size_of::<RevmBal>() +
976 bal.accounts.capacity() * core::mem::size_of::<(Address, RevmAccountBal)>() +
977 bal.accounts.values().map(revm_account_bal_heap_size).sum::<usize>()
978}
979
980fn revm_account_bal_heap_size(account: &RevmAccountBal) -> usize {
981 revm_account_info_bal_heap_size(&account.account_info) +
982 revm_storage_bal_heap_size(&account.storage)
983}
984
985fn revm_account_info_bal_heap_size(account_info: &RevmAccountInfoBal) -> usize {
986 revm_bal_writes_heap_size(&account_info.nonce, |_| 0) +
987 revm_bal_writes_heap_size(&account_info.balance, |_| 0) +
988 revm_bal_writes_heap_size(&account_info.code, revm_code_write_heap_size)
989}
990
991fn revm_storage_bal_heap_size(storage: &RevmStorageBal) -> usize {
992 storage.storage.len() * core::mem::size_of::<(StorageKey, RevmBalWrites<StorageValue>)>() +
993 storage
994 .storage
995 .values()
996 .map(|writes| revm_bal_writes_heap_size(writes, |_| 0))
997 .sum::<usize>()
998}
999
1000fn revm_bal_writes_heap_size<T, F>(writes: &RevmBalWrites<T>, mut item_heap_size: F) -> usize
1001where
1002 T: PartialEq + Clone,
1003 F: FnMut(&T) -> usize,
1004{
1005 writes.writes.capacity() * core::mem::size_of::<(u64, T)>() +
1006 writes.writes.iter().map(|(_, item)| item_heap_size(item)).sum::<usize>()
1007}
1008
1009fn revm_code_write_heap_size((_, bytecode): &(B256, Bytecode)) -> usize {
1010 bytecode.bytes_ref().len()
1011}
1012
1013#[cfg(test)]
1014mod tests {
1015 use super::*;
1016 use alloy_consensus::{transaction::TransactionMeta, Header};
1017 use alloy_eip7928::BlockAccessIndex;
1018 use alloy_eips::{BlockHashOrNumber, NumHash};
1019 use alloy_primitives::{Address, BlockHash, BlockNumber, Bytes, Signature, TxHash, TxNumber};
1020 use core::ops::{RangeBounds, RangeInclusive};
1021 use reth_db_models::StoredBlockBodyIndices;
1022 use reth_ethereum_primitives::{
1023 Block, BlockBody, EthPrimitives, Receipt, Transaction, TransactionSigned,
1024 };
1025 use reth_primitives_traits::{RecoveredBlock, SealedHeader};
1026 use reth_storage_api::{
1027 noop::NoopProvider, BalProvider, BalStore, BalStoreHandle, BlockBodyIndicesProvider,
1028 BlockHashReader, BlockNumReader, BlockReader, BlockSource, HeaderProvider, ReceiptProvider,
1029 TransactionVariant, TransactionsProvider,
1030 };
1031 use std::sync::atomic::{AtomicUsize, Ordering};
1032
1033 fn test_service() -> EthStateCacheService<NoopProvider, Runtime> {
1034 let (_cache, service) = EthStateCache::<EthPrimitives>::create(
1035 NoopProvider::default(),
1036 Runtime::test(),
1037 EthStateCacheConfig {
1038 max_blocks: 4,
1039 max_receipts: 4,
1040 max_headers: 4,
1041 max_bals: 4,
1042 max_concurrent_db_requests: 1,
1043 max_cached_tx_hashes: 16,
1044 },
1045 );
1046 service
1047 }
1048
1049 fn test_decoded_revm_bal() -> DecodedBal<Arc<RevmBal>> {
1050 DecodedBal::new(Arc::new(RevmBal::default()), Bytes::from_static(&[0xc0]))
1051 }
1052
1053 fn test_block() -> RecoveredBlock<Block> {
1054 RecoveredBlock::new_unhashed(
1055 Block {
1056 header: Header { number: 1, ..Default::default() },
1057 body: BlockBody {
1058 transactions: vec![TransactionSigned::new_unhashed(
1059 Transaction::Legacy(Default::default()),
1060 Signature::test_signature(),
1061 )],
1062 ..Default::default()
1063 },
1064 },
1065 vec![Address::ZERO],
1066 )
1067 }
1068
1069 #[test]
1070 fn reorg_evicts_cached_headers() {
1071 let mut service = test_service();
1072 let block_hash = B256::repeat_byte(0x11);
1073
1074 assert!(service
1075 .headers_cache
1076 .insert(block_hash, Header { number: 42, ..Default::default() }));
1077 assert!(service.headers_cache.get(&block_hash).is_some());
1078
1079 service.on_reorg_header(block_hash, Ok(Header { number: 7, ..Default::default() }));
1080
1081 assert!(service.headers_cache.get(&block_hash).is_none());
1082 }
1083
1084 #[test]
1085 fn reorg_forwards_header_to_queued_requests() {
1086 let mut service = test_service();
1087 let block_hash = B256::repeat_byte(0x22);
1088 let (response_tx, mut response_rx) = oneshot::channel();
1089 let header = Header { number: 7, ..Default::default() };
1090
1091 assert!(service.headers_cache.queue(block_hash, response_tx));
1092
1093 service.on_reorg_header(block_hash, Ok(header));
1094
1095 let header =
1096 response_rx.try_recv().expect("queued header response").expect("header result");
1097
1098 assert_eq!(header.number, 7);
1099 }
1100
1101 #[test]
1102 fn reorg_removes_tx_hash_index_entries_unconditionally() {
1103 let mut service = test_service();
1104 let block = test_block();
1105 let tx_hash = *block.body().transactions().next().expect("test transaction").tx_hash();
1106
1107 service.tx_hash_index.insert(tx_hash, (B256::repeat_byte(0x33), 0));
1108
1109 service.remove_block_transactions(&block);
1110
1111 assert!(service.tx_hash_index.get(&tx_hash).is_none());
1112 }
1113
1114 #[test]
1115 fn reorg_evicts_cached_bal() {
1116 let mut service = test_service();
1117 let block_hash = B256::repeat_byte(0x44);
1118
1119 assert!(service.bal_cache.insert(block_hash, CachedRevmBal::new(test_decoded_revm_bal())));
1120 assert!(service.bal_cache.get(&block_hash).is_some());
1121
1122 service.on_reorg_bal(block_hash, Ok(None));
1123
1124 assert!(service.bal_cache.get(&block_hash).is_none());
1125 }
1126
1127 #[test]
1128 fn reorg_forwards_bal_to_queued_requests() {
1129 let mut service = test_service();
1130 let block_hash = B256::repeat_byte(0x55);
1131 let (response_tx, mut response_rx) = oneshot::channel();
1132 let bal = CachedRevmBal::new(test_decoded_revm_bal());
1133
1134 assert!(service.bal_cache.queue(block_hash, response_tx));
1135
1136 service.on_reorg_bal(block_hash, Ok(Some(bal)));
1137
1138 let bal = response_rx.try_recv().expect("queued BAL response").expect("BAL result");
1139
1140 assert!(bal.is_some());
1141 }
1142
1143 #[test]
1144 fn cached_revm_bal_size_accounts_for_nested_allocations() {
1145 let mut account = RevmAccountBal::default();
1146 account.account_info.nonce.writes.push((BlockAccessIndex::new(1), 1));
1147 account
1148 .account_info
1149 .balance
1150 .writes
1151 .push((BlockAccessIndex::new(2), StorageValue::from(1u64)));
1152 account.account_info.code.writes.push((
1153 BlockAccessIndex::new(3),
1154 (B256::repeat_byte(0xaa), Bytecode::new_raw(Bytes::from_static(&[0x60, 0x00]))),
1155 ));
1156 account.storage.storage.insert(
1157 StorageKey::from(1u64),
1158 RevmBalWrites::new(vec![(BlockAccessIndex::new(4), StorageValue::from(2u64))]),
1159 );
1160
1161 let mut bal = RevmBal::default();
1162 bal.accounts.insert(Address::ZERO, account);
1163
1164 let raw = Bytes::from_static(&[0xc0, 0x01, 0x02]);
1165 let previous_estimate = core::mem::size_of::<CachedRevmBal>() +
1166 core::mem::size_of::<DecodedBal<Arc<RevmBal>>>() +
1167 raw.len() +
1168 core::mem::size_of::<RevmBal>();
1169 assert!(CachedRevmBal::new(DecodedBal::new(Arc::new(bal), raw)).size() > previous_estimate);
1170 }
1171
1172 #[tokio::test]
1173 async fn get_bal_uses_cached_revm_bal() {
1174 let fetches = Arc::new(AtomicUsize::default());
1175 let provider = TestBalProvider::new(fetches.clone());
1176 let cache = EthStateCache::<EthPrimitives>::spawn_with(
1177 provider,
1178 EthStateCacheConfig {
1179 max_blocks: 0,
1180 max_receipts: 0,
1181 max_headers: 0,
1182 max_bals: 4,
1183 max_concurrent_db_requests: 1,
1184 max_cached_tx_hashes: 0,
1185 },
1186 Runtime::test(),
1187 );
1188 let block_hash = B256::repeat_byte(0x66);
1189
1190 assert!(cache.get_bal(block_hash).await.unwrap().is_some());
1191 assert!(cache.get_bal(block_hash).await.unwrap().is_some());
1192
1193 assert_eq!(fetches.load(Ordering::SeqCst), 1);
1194 }
1195
1196 #[tokio::test]
1197 async fn concurrent_get_bal_requests_share_fetch() {
1198 let fetches = Arc::new(AtomicUsize::default());
1199 let provider = TestBalProvider::new(fetches.clone());
1200 let cache = EthStateCache::<EthPrimitives>::spawn_with(
1201 provider,
1202 EthStateCacheConfig {
1203 max_blocks: 0,
1204 max_receipts: 0,
1205 max_headers: 0,
1206 max_bals: 4,
1207 max_concurrent_db_requests: 1,
1208 max_cached_tx_hashes: 0,
1209 },
1210 Runtime::test(),
1211 );
1212 let block_hash = B256::repeat_byte(0x77);
1213
1214 let (first, second) = tokio::join!(cache.get_bal(block_hash), cache.get_bal(block_hash));
1215
1216 assert!(first.unwrap().is_some());
1217 assert!(second.unwrap().is_some());
1218 assert_eq!(fetches.load(Ordering::SeqCst), 1);
1219 }
1220
1221 #[derive(Clone, Debug, Default)]
1222 struct TestBalProvider {
1223 bal_store: BalStoreHandle,
1224 }
1225
1226 impl TestBalProvider {
1227 fn new(fetches: Arc<AtomicUsize>) -> Self {
1228 Self { bal_store: BalStoreHandle::new(TestBalStore { fetches }) }
1229 }
1230 }
1231
1232 impl BalProvider for TestBalProvider {
1233 fn bal_store(&self) -> &BalStoreHandle {
1234 &self.bal_store
1235 }
1236 }
1237
1238 #[derive(Debug)]
1239 struct TestBalStore {
1240 fetches: Arc<AtomicUsize>,
1241 }
1242
1243 impl BalStore for TestBalStore {
1244 fn insert(&self, _num_hash: NumHash, _bal: reth_storage_api::RawBal) -> ProviderResult<()> {
1245 Ok(())
1246 }
1247
1248 fn prune(&self, _tip: BlockNumber) -> ProviderResult<usize> {
1249 Ok(0)
1250 }
1251
1252 fn get_by_hashes(&self, block_hashes: &[BlockHash]) -> ProviderResult<Vec<Option<Bytes>>> {
1253 self.fetches.fetch_add(1, Ordering::SeqCst);
1254 Ok(block_hashes.iter().map(|_| Some(Bytes::from_static(&[0xc0]))).collect())
1255 }
1256
1257 fn bal_stream(&self) -> reth_storage_api::BalNotificationStream {
1258 reth_storage_api::NoopBalStore.bal_stream()
1259 }
1260 }
1261
1262 impl BlockHashReader for TestBalProvider {
1263 fn block_hash(&self, _number: BlockNumber) -> ProviderResult<Option<B256>> {
1264 Ok(None)
1265 }
1266
1267 fn canonical_hashes_range(
1268 &self,
1269 _start: BlockNumber,
1270 _end: BlockNumber,
1271 ) -> ProviderResult<Vec<B256>> {
1272 Ok(Vec::new())
1273 }
1274 }
1275
1276 impl BlockNumReader for TestBalProvider {
1277 fn chain_info(&self) -> ProviderResult<reth_chainspec::ChainInfo> {
1278 Ok(reth_chainspec::ChainInfo::default())
1279 }
1280
1281 fn best_block_number(&self) -> ProviderResult<BlockNumber> {
1282 Ok(0)
1283 }
1284
1285 fn last_block_number(&self) -> ProviderResult<BlockNumber> {
1286 Ok(0)
1287 }
1288
1289 fn block_number(&self, _hash: B256) -> ProviderResult<Option<BlockNumber>> {
1290 Ok(None)
1291 }
1292 }
1293
1294 impl HeaderProvider for TestBalProvider {
1295 type Header = Header;
1296
1297 fn header(&self, _block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
1298 Ok(None)
1299 }
1300
1301 fn header_by_number(&self, _num: u64) -> ProviderResult<Option<Self::Header>> {
1302 Ok(None)
1303 }
1304
1305 fn headers_range(
1306 &self,
1307 _range: impl RangeBounds<BlockNumber>,
1308 ) -> ProviderResult<Vec<Self::Header>> {
1309 Ok(Vec::new())
1310 }
1311
1312 fn sealed_header(
1313 &self,
1314 _number: BlockNumber,
1315 ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
1316 Ok(None)
1317 }
1318
1319 fn sealed_headers_while(
1320 &self,
1321 _range: impl RangeBounds<BlockNumber>,
1322 _predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
1323 ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
1324 Ok(Vec::new())
1325 }
1326 }
1327
1328 impl BlockBodyIndicesProvider for TestBalProvider {
1329 fn block_body_indices(&self, _num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
1330 Ok(None)
1331 }
1332
1333 fn block_body_indices_range(
1334 &self,
1335 _range: RangeInclusive<BlockNumber>,
1336 ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
1337 Ok(Vec::new())
1338 }
1339 }
1340
1341 impl TransactionsProvider for TestBalProvider {
1342 type Transaction = TransactionSigned;
1343
1344 fn transaction_id(&self, _tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
1345 Ok(None)
1346 }
1347
1348 fn transaction_by_id(&self, _id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
1349 Ok(None)
1350 }
1351
1352 fn transaction_by_id_unhashed(
1353 &self,
1354 _id: TxNumber,
1355 ) -> ProviderResult<Option<Self::Transaction>> {
1356 Ok(None)
1357 }
1358
1359 fn transaction_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
1360 Ok(None)
1361 }
1362
1363 fn transaction_by_hash_with_meta(
1364 &self,
1365 _hash: TxHash,
1366 ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
1367 Ok(None)
1368 }
1369
1370 fn transactions_by_block(
1371 &self,
1372 _block: BlockHashOrNumber,
1373 ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
1374 Ok(None)
1375 }
1376
1377 fn transactions_by_block_range(
1378 &self,
1379 _range: impl RangeBounds<BlockNumber>,
1380 ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
1381 Ok(Vec::new())
1382 }
1383
1384 fn transactions_by_tx_range(
1385 &self,
1386 _range: impl RangeBounds<TxNumber>,
1387 ) -> ProviderResult<Vec<Self::Transaction>> {
1388 Ok(Vec::new())
1389 }
1390
1391 fn senders_by_tx_range(
1392 &self,
1393 _range: impl RangeBounds<TxNumber>,
1394 ) -> ProviderResult<Vec<Address>> {
1395 Ok(Vec::new())
1396 }
1397
1398 fn transaction_sender(&self, _id: TxNumber) -> ProviderResult<Option<Address>> {
1399 Ok(None)
1400 }
1401 }
1402
1403 impl ReceiptProvider for TestBalProvider {
1404 type Receipt = Receipt;
1405
1406 fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
1407 Ok(None)
1408 }
1409
1410 fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
1411 Ok(None)
1412 }
1413
1414 fn receipts_by_block(
1415 &self,
1416 _block: BlockHashOrNumber,
1417 ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
1418 Ok(None)
1419 }
1420
1421 fn receipts_by_tx_range(
1422 &self,
1423 _range: impl RangeBounds<TxNumber>,
1424 ) -> ProviderResult<Vec<Self::Receipt>> {
1425 Ok(Vec::new())
1426 }
1427
1428 fn receipts_by_block_range(
1429 &self,
1430 _block_range: RangeInclusive<BlockNumber>,
1431 ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
1432 Ok(Vec::new())
1433 }
1434 }
1435
1436 impl BlockReader for TestBalProvider {
1437 type Block = Block;
1438
1439 fn find_block_by_hash(
1440 &self,
1441 _hash: B256,
1442 _source: BlockSource,
1443 ) -> ProviderResult<Option<Self::Block>> {
1444 Ok(None)
1445 }
1446
1447 fn block(&self, _id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
1448 Ok(None)
1449 }
1450
1451 fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
1452 Ok(None)
1453 }
1454
1455 fn pending_block_and_receipts(
1456 &self,
1457 ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
1458 Ok(None)
1459 }
1460
1461 fn recovered_block(
1462 &self,
1463 _id: BlockHashOrNumber,
1464 _transaction_kind: TransactionVariant,
1465 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
1466 Ok(None)
1467 }
1468
1469 fn sealed_block_with_senders(
1470 &self,
1471 _id: BlockHashOrNumber,
1472 _transaction_kind: TransactionVariant,
1473 ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
1474 Ok(None)
1475 }
1476
1477 fn block_range(
1478 &self,
1479 _range: RangeInclusive<BlockNumber>,
1480 ) -> ProviderResult<Vec<Self::Block>> {
1481 Ok(Vec::new())
1482 }
1483
1484 fn block_with_senders_range(
1485 &self,
1486 _range: RangeInclusive<BlockNumber>,
1487 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
1488 Ok(Vec::new())
1489 }
1490
1491 fn recovered_block_range(
1492 &self,
1493 _range: RangeInclusive<BlockNumber>,
1494 ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
1495 Ok(Vec::new())
1496 }
1497
1498 fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
1499 Ok(None)
1500 }
1501 }
1502}