Skip to main content

reth_storage_rpc_provider/
lib.rs

1//! # RPC Blockchain Provider for Reth
2//!
3//! This crate provides an RPC-based implementation of reth's `StateProviderFactory` and related
4//! traits that fetches blockchain data via RPC instead of from a local database.
5//!
6//! Similar to the [`BlockchainProvider`](../../provider/src/providers/blockchain_provider.rs)
7//! which provides access to local blockchain data, this crate offers the same functionality but for
8//! remote blockchain access via RPC.
9//!
10//! Originally created by [cakevm](https://github.com/cakevm/alloy-reth-provider).
11//!
12//! ## Features
13//!
14//! - Implements `StateProviderFactory` for remote RPC state access
15//! - Supports Ethereum and Optimism network
16//! - Useful for testing without requiring a full database
17//! - Can be used with reth ExEx (Execution Extensions) for testing
18
19#![doc(
20    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
21    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
22    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
23)]
24#![cfg_attr(not(test), warn(unused_crate_dependencies))]
25#![cfg_attr(docsrs, feature(doc_cfg))]
26
27use alloy_consensus::{constants::KECCAK_EMPTY, transaction::TransactionMeta, BlockHeader};
28use alloy_eips::BlockHashOrNumber;
29use alloy_network::{primitives::HeaderResponse, BlockResponse};
30use alloy_primitives::{Address, BlockHash, BlockNumber, StorageKey, TxHash, TxNumber, B256, U256};
31use alloy_provider::{ext::DebugApi, network::Network, Provider};
32use alloy_rpc_types::BlockId;
33use alloy_rpc_types_engine::ForkchoiceState;
34use alloy_rpc_types_eth::AccountInfo;
35use dashmap::DashMap;
36use reth_chain_state::ExecutedBlock;
37use reth_chainspec::{ChainInfo, ChainSpecProvider};
38use reth_db_api::{
39    mock::{DatabaseMock, TxMock},
40    models::StoredBlockBodyIndices,
41};
42use reth_errors::{ProviderError, ProviderResult};
43use reth_execution_types::RecoveredBlockAndExecutionOutput;
44use reth_node_types::{
45    Block, BlockBody, BlockTy, HeaderTy, NodeTypes, PrimitivesTy, ReceiptTy, TxTy,
46};
47use reth_primitives_traits::{Account, Bytecode, RecoveredBlock, SealedHeader};
48use reth_provider::{
49    AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BytecodeReader,
50    CanonChainTracker, CanonStateNotification, CanonStateNotifications, CanonStateSubscriptions,
51    ChainStateBlockReader, ChainStateBlockWriter, ChangeSetReader, DatabaseProviderFactory,
52    HeaderProvider, PruneCheckpointReader, ReceiptProvider, StageCheckpointReader, StateProvider,
53    StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, StorageReader,
54    TransactionVariant, TransactionsProvider,
55};
56use reth_prune_types::{PruneCheckpoint, PruneSegment};
57pub mod rpc_response;
58use reth_stages_types::{StageCheckpoint, StageId};
59use reth_storage_api::{
60    BlockBodyIndicesProvider, BlockReaderIdExt, BlockSource, DBProvider, DbTxProvider,
61    NodePrimitivesProvider, ReceiptProviderIdExt, StatsReader,
62};
63use reth_trie::{
64    updates::TrieUpdates, AccountProof, HashedPostState, KeccakKeyHasher, MultiProof, TrieInput,
65};
66pub use rpc_response::{EthRpcConverter, RpcResponseConverter};
67use std::{
68    collections::BTreeMap,
69    future::{Future, IntoFuture},
70    ops::{RangeBounds, RangeInclusive},
71    sync::Arc,
72};
73use tokio::{runtime::Handle, sync::broadcast};
74use tracing::{trace, warn};
75
76/// Configuration for `RpcBlockchainProvider`
77#[derive(Debug, Clone)]
78pub struct RpcBlockchainProviderConfig {
79    /// Whether to compute state root when creating execution outcomes
80    pub compute_state_root: bool,
81    /// Whether to use Reth-specific RPC methods for better performance
82    ///
83    /// If enabled, the node will use Reth's RPC methods (`debug_codeByHash` and
84    /// `eth_getAccountInfo`) to speed up account information retrieval. When disabled, it will
85    /// use multiple standard RPC calls to get account information.
86    pub reth_rpc_support: bool,
87}
88
89impl Default for RpcBlockchainProviderConfig {
90    fn default() -> Self {
91        Self { compute_state_root: false, reth_rpc_support: true }
92    }
93}
94
95impl RpcBlockchainProviderConfig {
96    /// Sets whether to compute state root when creating execution outcomes
97    pub const fn with_compute_state_root(mut self, compute: bool) -> Self {
98        self.compute_state_root = compute;
99        self
100    }
101
102    /// Sets whether to use Reth-specific RPC methods for better performance
103    pub const fn with_reth_rpc_support(mut self, support: bool) -> Self {
104        self.reth_rpc_support = support;
105        self
106    }
107}
108
109/// Type-erased RPC response converter stored in [`RpcBlockchainProvider`].
110type DynRpcConverter<Node, N> = dyn RpcResponseConverter<
111    N,
112    Block = BlockTy<Node>,
113    Transaction = TxTy<Node>,
114    Receipt = ReceiptTy<Node>,
115>;
116
117/// An RPC-based blockchain provider that fetches blockchain data via remote RPC calls.
118///
119/// This is the RPC equivalent of
120/// [`BlockchainProvider`](../../provider/src/providers/blockchain_provider.rs), implementing
121/// the same `StateProviderFactory` and related traits but fetching data from a remote node instead
122/// of local storage.
123///
124/// This provider is useful for:
125/// - Testing without requiring a full local database
126/// - Accessing blockchain state from remote nodes
127/// - Building light clients or tools that don't need full node storage
128///
129/// The provider type is generic over the network type N (defaulting to `AnyNetwork`),
130/// but the current implementation is specialized for `alloy_network::AnyNetwork`
131/// as it needs to access block header fields directly.
132#[derive(Clone)]
133pub struct RpcBlockchainProvider<P, Node, N = alloy_network::AnyNetwork>
134where
135    Node: NodeTypes,
136    N: Network,
137{
138    /// The underlying Alloy provider
139    provider: P,
140    /// Node types marker
141    node_types: std::marker::PhantomData<Node>,
142    /// Network marker
143    network: std::marker::PhantomData<N>,
144    /// Broadcast channel for canon state notifications
145    canon_state_notification: broadcast::Sender<CanonStateNotification<PrimitivesTy<Node>>>,
146    /// Configuration for the provider
147    config: RpcBlockchainProviderConfig,
148    /// Cached chain spec
149    chain_spec: Arc<Node::ChainSpec>,
150    /// Converts RPC responses to primitive types.
151    converter: Arc<DynRpcConverter<Node, N>>,
152}
153
154impl<P, Node: NodeTypes, N: Network> std::fmt::Debug for RpcBlockchainProvider<P, Node, N> {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        f.debug_struct("RpcBlockchainProvider").field("config", &self.config).finish()
157    }
158}
159
160impl<P, Node: NodeTypes, N: Network> RpcBlockchainProvider<P, Node, N>
161where
162    EthRpcConverter: RpcResponseConverter<
163        N,
164        Block = BlockTy<Node>,
165        Transaction = TxTy<Node>,
166        Receipt = ReceiptTy<Node>,
167    >,
168{
169    /// Creates a new `RpcBlockchainProvider` with the default [`EthRpcConverter`].
170    pub fn new(provider: P) -> Self
171    where
172        Node::ChainSpec: Default,
173    {
174        Self::new_with_converter(provider, EthRpcConverter)
175    }
176}
177
178impl<P, Node: NodeTypes, N: Network> RpcBlockchainProvider<P, Node, N> {
179    /// Creates a new `RpcBlockchainProvider` with default configuration and the given converter.
180    pub fn new_with_converter(
181        provider: P,
182        converter: impl RpcResponseConverter<
183            N,
184            Block = BlockTy<Node>,
185            Transaction = TxTy<Node>,
186            Receipt = ReceiptTy<Node>,
187        >,
188    ) -> Self
189    where
190        Node::ChainSpec: Default,
191    {
192        Self::new_with_converter_and_config(
193            provider,
194            converter,
195            RpcBlockchainProviderConfig::default(),
196        )
197    }
198
199    /// Creates a new `RpcBlockchainProvider` with custom configuration and the given converter.
200    pub fn new_with_converter_and_config(
201        provider: P,
202        converter: impl RpcResponseConverter<
203            N,
204            Block = BlockTy<Node>,
205            Transaction = TxTy<Node>,
206            Receipt = ReceiptTy<Node>,
207        >,
208        config: RpcBlockchainProviderConfig,
209    ) -> Self
210    where
211        Node::ChainSpec: Default,
212    {
213        let (canon_state_notification, _) = broadcast::channel(1);
214        Self {
215            provider,
216            node_types: std::marker::PhantomData,
217            network: std::marker::PhantomData,
218            canon_state_notification,
219            config,
220            chain_spec: Arc::new(Node::ChainSpec::default()),
221            converter: Arc::new(converter),
222        }
223    }
224
225    /// Use a custom chain spec for the provider
226    pub fn with_chain_spec(self, chain_spec: Arc<Node::ChainSpec>) -> Self {
227        Self { chain_spec, ..self }
228    }
229
230    /// Helper function to execute async operations in a blocking context
231    fn block_on_async<F, T>(&self, fut: F) -> T
232    where
233        F: Future<Output = T>,
234    {
235        tokio::task::block_in_place(move || Handle::current().block_on(fut))
236    }
237
238    /// Get a reference to the canon state notification sender
239    pub const fn canon_state_notification(
240        &self,
241    ) -> &broadcast::Sender<CanonStateNotification<PrimitivesTy<Node>>> {
242        &self.canon_state_notification
243    }
244}
245
246impl<P, Node, N> RpcBlockchainProvider<P, Node, N>
247where
248    P: Provider<N> + Clone + 'static,
249    N: Network,
250    Node: NodeTypes,
251{
252    /// Helper function to create a state provider for a given block ID
253    fn create_state_provider(&self, block_id: BlockId) -> RpcBlockchainStateProvider<P, Node, N> {
254        RpcBlockchainStateProvider::with_chain_spec(
255            self.provider.clone(),
256            block_id,
257            self.chain_spec.clone(),
258        )
259        .with_compute_state_root(self.config.compute_state_root)
260        .with_reth_rpc_support(self.config.reth_rpc_support)
261    }
262
263    /// Helper function to get state provider by block number
264    fn state_by_block_number(
265        &self,
266        block_number: BlockNumber,
267    ) -> Result<StateProviderBox, ProviderError> {
268        Ok(Box::new(self.create_state_provider(BlockId::number(block_number))))
269    }
270}
271
272// Implementation note: While the types are generic over Network N, the trait implementations
273// are specialized for AnyNetwork because they need to access block header fields.
274// This allows the types to be instantiated with any network while the actual functionality
275// requires AnyNetwork. Future improvements could add trait bounds for networks with
276// compatible block structures.
277impl<P, Node, N> BlockHashReader for RpcBlockchainProvider<P, Node, N>
278where
279    P: Provider<N> + Clone + 'static,
280    N: Network,
281    Node: NodeTypes,
282{
283    fn block_hash(&self, number: BlockNumber) -> Result<Option<B256>, ProviderError> {
284        let block = self.block_on_async(async {
285            self.provider.get_block_by_number(number.into()).await.map_err(ProviderError::other)
286        })?;
287        Ok(block.map(|b| b.header().hash()))
288    }
289
290    fn canonical_hashes_range(
291        &self,
292        _start: BlockNumber,
293        _end: BlockNumber,
294    ) -> Result<Vec<B256>, ProviderError> {
295        // Would need to make multiple RPC calls
296        Err(ProviderError::UnsupportedProvider)
297    }
298}
299
300impl<P, Node, N> BlockNumReader for RpcBlockchainProvider<P, Node, N>
301where
302    P: Provider<N> + Clone + 'static,
303    N: Network,
304    Node: NodeTypes,
305{
306    fn chain_info(&self) -> Result<reth_chainspec::ChainInfo, ProviderError> {
307        self.block_on_async(async {
308            let block = self
309                .provider
310                .get_block(BlockId::latest())
311                .await
312                .map_err(ProviderError::other)?
313                .ok_or(ProviderError::HeaderNotFound(0.into()))?;
314
315            Ok(ChainInfo { best_hash: block.header().hash(), best_number: block.header().number() })
316        })
317    }
318
319    fn best_block_number(&self) -> Result<BlockNumber, ProviderError> {
320        self.block_on_async(async {
321            self.provider.get_block_number().await.map_err(ProviderError::other)
322        })
323    }
324
325    fn last_block_number(&self) -> Result<BlockNumber, ProviderError> {
326        self.best_block_number()
327    }
328
329    fn block_number(&self, hash: B256) -> Result<Option<BlockNumber>, ProviderError> {
330        let block = self.block_on_async(async {
331            self.provider.get_block_by_hash(hash).await.map_err(ProviderError::other)
332        })?;
333        Ok(block.map(|b| b.header().number()))
334    }
335}
336
337impl<P, Node, N> BlockIdReader for RpcBlockchainProvider<P, Node, N>
338where
339    P: Provider<N> + Clone + 'static,
340    N: Network,
341    Node: NodeTypes,
342{
343    fn block_number_for_id(&self, block_id: BlockId) -> Result<Option<BlockNumber>, ProviderError> {
344        match block_id {
345            BlockId::Hash(hash) => {
346                let block = self.block_on_async(async {
347                    self.provider
348                        .get_block_by_hash(hash.block_hash)
349                        .await
350                        .map_err(ProviderError::other)
351                })?;
352                Ok(block.map(|b| b.header().number()))
353            }
354            BlockId::Number(number_or_tag) => match number_or_tag {
355                alloy_rpc_types::BlockNumberOrTag::Number(num) => Ok(Some(num)),
356                alloy_rpc_types::BlockNumberOrTag::Latest => self.block_on_async(async {
357                    self.provider.get_block_number().await.map(Some).map_err(ProviderError::other)
358                }),
359                _ => Ok(None),
360            },
361        }
362    }
363
364    fn pending_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
365        // RPC doesn't provide pending block number and hash together
366        Err(ProviderError::UnsupportedProvider)
367    }
368
369    fn safe_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
370        // RPC doesn't provide safe block number and hash
371        Err(ProviderError::UnsupportedProvider)
372    }
373
374    fn finalized_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
375        // RPC doesn't provide finalized block number and hash
376        Err(ProviderError::UnsupportedProvider)
377    }
378}
379
380impl<P, Node, N> HeaderProvider for RpcBlockchainProvider<P, Node, N>
381where
382    P: Provider<N> + Clone + 'static,
383    N: Network,
384    Node: NodeTypes,
385{
386    type Header = HeaderTy<Node>;
387
388    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
389        let block_response = self.block_on_async(async {
390            self.provider.get_block_by_hash(block_hash).await.map_err(ProviderError::other)
391        })?;
392
393        let Some(block_response) = block_response else {
394            // If the block was not found, return None
395            return Ok(None);
396        };
397
398        // Convert the network block response to primitive block
399        let block = self.converter.block(block_response).map_err(ProviderError::other)?;
400
401        Ok(Some(block.into_header()))
402    }
403
404    fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
405        let Some(sealed_header) = self.sealed_header(num)? else {
406            // If the block was not found, return None
407            return Ok(None);
408        };
409
410        Ok(Some(sealed_header.into_header()))
411    }
412
413    fn headers_range(
414        &self,
415        _range: impl RangeBounds<BlockNumber>,
416    ) -> ProviderResult<Vec<Self::Header>> {
417        Err(ProviderError::UnsupportedProvider)
418    }
419
420    fn sealed_header(
421        &self,
422        number: BlockNumber,
423    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
424        let block_response = self.block_on_async(async {
425            self.provider.get_block_by_number(number.into()).await.map_err(ProviderError::other)
426        })?;
427
428        let Some(block_response) = block_response else {
429            // If the block was not found, return None
430            return Ok(None);
431        };
432        let block_hash = block_response.header().hash();
433
434        // Convert the network block response to primitive block
435        let block = self.converter.block(block_response).map_err(ProviderError::other)?;
436
437        Ok(Some(SealedHeader::new(block.into_header(), block_hash)))
438    }
439
440    fn sealed_headers_while(
441        &self,
442        _range: impl RangeBounds<BlockNumber>,
443        _predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
444    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
445        Err(ProviderError::UnsupportedProvider)
446    }
447}
448
449impl<P, Node, N> BlockBodyIndicesProvider for RpcBlockchainProvider<P, Node, N>
450where
451    P: Provider<N> + Clone + 'static,
452    N: Network,
453    Node: NodeTypes,
454{
455    fn block_body_indices(&self, _num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
456        Err(ProviderError::UnsupportedProvider)
457    }
458
459    fn block_body_indices_range(
460        &self,
461        _range: RangeInclusive<BlockNumber>,
462    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
463        Err(ProviderError::UnsupportedProvider)
464    }
465}
466
467impl<P, Node, N> BlockReader for RpcBlockchainProvider<P, Node, N>
468where
469    P: Provider<N> + Clone + 'static,
470    N: Network,
471    Node: NodeTypes,
472{
473    type Block = BlockTy<Node>;
474
475    fn find_block_by_hash(
476        &self,
477        _hash: B256,
478        _source: BlockSource,
479    ) -> ProviderResult<Option<Self::Block>> {
480        Err(ProviderError::UnsupportedProvider)
481    }
482
483    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
484        let block_response = self.block_on_async(async {
485            self.provider.get_block(id.into()).full().await.map_err(ProviderError::other)
486        })?;
487
488        let Some(block_response) = block_response else {
489            // If the block was not found, return None
490            return Ok(None);
491        };
492
493        // Convert the network block response to primitive block
494        let block = self.converter.block(block_response).map_err(ProviderError::other)?;
495
496        Ok(Some(block))
497    }
498
499    fn pending_block(&self) -> ProviderResult<Option<Arc<RecoveredBlock<Self::Block>>>> {
500        Err(ProviderError::UnsupportedProvider)
501    }
502
503    fn pending_block_and_receipts(
504        &self,
505    ) -> ProviderResult<Option<RecoveredBlockAndExecutionOutput<Self::Block, Self::Receipt>>> {
506        Err(ProviderError::UnsupportedProvider)
507    }
508
509    fn recovered_block(
510        &self,
511        _id: BlockHashOrNumber,
512        _transaction_kind: TransactionVariant,
513    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
514        Err(ProviderError::UnsupportedProvider)
515    }
516
517    fn sealed_block_with_senders(
518        &self,
519        _id: BlockHashOrNumber,
520        _transaction_kind: TransactionVariant,
521    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
522        Err(ProviderError::UnsupportedProvider)
523    }
524
525    fn block_range(&self, _range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
526        Err(ProviderError::UnsupportedProvider)
527    }
528
529    fn block_with_senders_range(
530        &self,
531        _range: RangeInclusive<BlockNumber>,
532    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
533        Err(ProviderError::UnsupportedProvider)
534    }
535
536    fn recovered_block_range(
537        &self,
538        _range: RangeInclusive<BlockNumber>,
539    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
540        Err(ProviderError::UnsupportedProvider)
541    }
542
543    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
544        Err(ProviderError::UnsupportedProvider)
545    }
546}
547
548impl<P, Node, N> BlockReaderIdExt for RpcBlockchainProvider<P, Node, N>
549where
550    P: Provider<N> + Clone + 'static,
551    N: Network,
552    Node: NodeTypes,
553{
554    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
555        match id {
556            BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
557            BlockId::Number(number_or_tag) => self.block_by_number_or_tag(number_or_tag),
558        }
559    }
560
561    fn sealed_header_by_id(
562        &self,
563        id: BlockId,
564    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
565        match id {
566            BlockId::Hash(hash) => self.sealed_header_by_hash(hash.block_hash),
567            BlockId::Number(number_or_tag) => self.sealed_header_by_number_or_tag(number_or_tag),
568        }
569    }
570
571    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
572        match id {
573            BlockId::Hash(hash) => self.header_by_hash_or_number(hash.block_hash.into()),
574            BlockId::Number(number_or_tag) => self.header_by_number_or_tag(number_or_tag),
575        }
576    }
577}
578
579impl<P, Node, N> ReceiptProvider for RpcBlockchainProvider<P, Node, N>
580where
581    P: Provider<N> + Clone + 'static,
582    N: Network,
583    Node: NodeTypes,
584{
585    type Receipt = ReceiptTy<Node>;
586
587    fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
588        Err(ProviderError::UnsupportedProvider)
589    }
590
591    fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
592        let receipt_response = self.block_on_async(async {
593            self.provider.get_transaction_receipt(hash).await.map_err(ProviderError::other)
594        })?;
595
596        let Some(receipt_response) = receipt_response else {
597            return Ok(None);
598        };
599
600        let receipt = self.converter.receipt(receipt_response).map_err(ProviderError::other)?;
601        Ok(Some(receipt))
602    }
603
604    fn receipts_by_block(
605        &self,
606        block: BlockHashOrNumber,
607    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
608        self.block_on_async(async {
609            let receipts_response = self
610                .provider
611                .get_block_receipts(block.into())
612                .await
613                .map_err(ProviderError::other)?;
614
615            let Some(receipts) = receipts_response else {
616                return Ok(None);
617            };
618
619            let receipts = receipts
620                .into_iter()
621                .map(|r| self.converter.receipt(r).map_err(ProviderError::other))
622                .collect::<Result<Vec<_>, _>>()?;
623
624            Ok(Some(receipts))
625        })
626    }
627
628    fn receipts_by_tx_range(
629        &self,
630        _range: impl RangeBounds<TxNumber>,
631    ) -> ProviderResult<Vec<Self::Receipt>> {
632        Err(ProviderError::UnsupportedProvider)
633    }
634
635    fn receipts_by_block_range(
636        &self,
637        _block_range: RangeInclusive<BlockNumber>,
638    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
639        Err(ProviderError::UnsupportedProvider)
640    }
641}
642
643impl<P, Node, N> ReceiptProviderIdExt for RpcBlockchainProvider<P, Node, N>
644where
645    P: Provider<N> + Clone + 'static,
646    N: Network,
647    Node: NodeTypes,
648{
649}
650
651impl<P, Node, N> TransactionsProvider for RpcBlockchainProvider<P, Node, N>
652where
653    P: Provider<N> + Clone + 'static,
654    N: Network,
655    Node: NodeTypes,
656{
657    type Transaction = TxTy<Node>;
658
659    fn transaction_id(&self, _tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
660        Err(ProviderError::UnsupportedProvider)
661    }
662
663    fn transaction_by_id(&self, _id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
664        Err(ProviderError::UnsupportedProvider)
665    }
666
667    fn transaction_by_id_unhashed(
668        &self,
669        _id: TxNumber,
670    ) -> ProviderResult<Option<Self::Transaction>> {
671        Err(ProviderError::UnsupportedProvider)
672    }
673
674    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
675        let transaction_response = self.block_on_async(async {
676            self.provider.get_transaction_by_hash(hash).await.map_err(ProviderError::other)
677        })?;
678
679        let Some(transaction_response) = transaction_response else {
680            return Ok(None);
681        };
682
683        let transaction =
684            self.converter.transaction(transaction_response).map_err(ProviderError::other)?;
685        Ok(Some(transaction))
686    }
687
688    fn transaction_by_hash_with_meta(
689        &self,
690        _hash: TxHash,
691    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
692        Err(ProviderError::UnsupportedProvider)
693    }
694
695    fn transactions_by_block(
696        &self,
697        block: BlockHashOrNumber,
698    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
699        let block_response = self.block_on_async(async {
700            self.provider.get_block(block.into()).full().await.map_err(ProviderError::other)
701        })?;
702
703        let Some(block_response) = block_response else {
704            return Ok(None);
705        };
706
707        let block = self.converter.block(block_response).map_err(ProviderError::other)?;
708        Ok(Some(block.into_body().into_transactions()))
709    }
710
711    fn transactions_by_block_range(
712        &self,
713        _range: impl RangeBounds<BlockNumber>,
714    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
715        Err(ProviderError::UnsupportedProvider)
716    }
717
718    fn transactions_by_tx_range(
719        &self,
720        _range: impl RangeBounds<TxNumber>,
721    ) -> ProviderResult<Vec<Self::Transaction>> {
722        Err(ProviderError::UnsupportedProvider)
723    }
724
725    fn senders_by_tx_range(
726        &self,
727        _range: impl RangeBounds<TxNumber>,
728    ) -> ProviderResult<Vec<Address>> {
729        Err(ProviderError::UnsupportedProvider)
730    }
731
732    fn transaction_sender(&self, _id: TxNumber) -> ProviderResult<Option<Address>> {
733        Err(ProviderError::UnsupportedProvider)
734    }
735}
736
737impl<P, Node, N> StateProviderFactory for RpcBlockchainProvider<P, Node, N>
738where
739    P: Provider<N> + Clone + 'static,
740    N: Network,
741    Node: NodeTypes,
742{
743    type Primitives = PrimitivesTy<Node>;
744
745    fn latest(&self) -> Result<StateProviderBox, ProviderError> {
746        Ok(Box::new(self.create_state_provider(self.best_block_number()?.into())))
747    }
748
749    fn state_with_block_appended(
750        &self,
751        _parent_hash: BlockHash,
752        _block: ExecutedBlock<PrimitivesTy<Node>>,
753    ) -> ProviderResult<StateProviderBox> {
754        Err(ProviderError::UnsupportedProvider)
755    }
756
757    fn state_by_block_id(&self, block_id: BlockId) -> Result<StateProviderBox, ProviderError> {
758        Ok(Box::new(self.create_state_provider(block_id)))
759    }
760
761    fn state_by_block_number_or_tag(
762        &self,
763        number_or_tag: alloy_rpc_types::BlockNumberOrTag,
764    ) -> Result<StateProviderBox, ProviderError> {
765        match number_or_tag {
766            alloy_rpc_types::BlockNumberOrTag::Latest => self.latest(),
767            alloy_rpc_types::BlockNumberOrTag::Pending => self.pending(),
768            alloy_rpc_types::BlockNumberOrTag::Number(num) => self.state_by_block_number(num),
769            _ => Err(ProviderError::UnsupportedProvider),
770        }
771    }
772
773    fn history_by_block_number(
774        &self,
775        block_number: BlockNumber,
776    ) -> Result<StateProviderBox, ProviderError> {
777        self.state_by_block_number(block_number)
778    }
779
780    fn history_by_block_hash(
781        &self,
782        block_hash: BlockHash,
783    ) -> Result<StateProviderBox, ProviderError> {
784        self.state_by_block_hash(block_hash)
785    }
786
787    fn state_by_block_hash(
788        &self,
789        block_hash: BlockHash,
790    ) -> Result<StateProviderBox, ProviderError> {
791        trace!(target: "alloy-provider", ?block_hash, "Getting state provider by block hash");
792
793        let block = self.block_on_async(async {
794            self.provider
795                .get_block_by_hash(block_hash)
796                .await
797                .map_err(ProviderError::other)?
798                .ok_or(ProviderError::BlockHashNotFound(block_hash))
799        })?;
800
801        let block_number = block.header().number();
802        Ok(Box::new(self.create_state_provider(BlockId::number(block_number))))
803    }
804
805    fn pending(&self) -> Result<StateProviderBox, ProviderError> {
806        trace!(target: "alloy-provider", "Getting pending state provider");
807        self.latest()
808    }
809
810    fn pending_state_by_hash(
811        &self,
812        _block_hash: B256,
813    ) -> Result<Option<StateProviderBox>, ProviderError> {
814        // RPC provider doesn't support pending state by hash
815        Err(ProviderError::UnsupportedProvider)
816    }
817
818    fn maybe_pending(&self) -> Result<Option<StateProviderBox>, ProviderError> {
819        Ok(None)
820    }
821}
822
823impl<P, Node, N> DatabaseProviderFactory for RpcBlockchainProvider<P, Node, N>
824where
825    P: Provider<N> + Clone + 'static,
826    N: Network,
827    Node: NodeTypes,
828{
829    type DB = DatabaseMock;
830    type Provider = RpcBlockchainStateProvider<P, Node, N>;
831    type ProviderRW = RpcBlockchainStateProvider<P, Node, N>;
832
833    fn database_provider_ro(&self) -> Result<Self::Provider, ProviderError> {
834        // RPC provider returns a new state provider
835        let block_number = self.block_on_async(async {
836            self.provider.get_block_number().await.map_err(ProviderError::other)
837        })?;
838
839        Ok(self.create_state_provider(BlockId::number(block_number)))
840    }
841
842    fn database_provider_rw(&self) -> Result<Self::ProviderRW, ProviderError> {
843        // RPC provider returns a new state provider
844        let block_number = self.block_on_async(async {
845            self.provider.get_block_number().await.map_err(ProviderError::other)
846        })?;
847
848        Ok(self.create_state_provider(BlockId::number(block_number)))
849    }
850}
851
852impl<P, Node, N> CanonChainTracker for RpcBlockchainProvider<P, Node, N>
853where
854    P: Provider<N> + Clone + 'static,
855    N: Network,
856    Node: NodeTypes,
857{
858    type Header = alloy_consensus::Header;
859    fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
860        // No-op for RPC provider
861    }
862
863    fn last_received_update_timestamp(&self) -> Option<std::time::Instant> {
864        None
865    }
866
867    fn set_canonical_head(&self, _header: SealedHeader<Self::Header>) {
868        // No-op for RPC provider
869    }
870
871    fn set_safe(&self, _header: SealedHeader<Self::Header>) {
872        // No-op for RPC provider
873    }
874
875    fn set_finalized(&self, _header: SealedHeader<Self::Header>) {
876        // No-op for RPC provider
877    }
878}
879
880impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainProvider<P, Node, N>
881where
882    P: Send + Sync,
883    N: Network,
884    Node: NodeTypes,
885{
886    type Primitives = PrimitivesTy<Node>;
887}
888
889impl<P, Node, N> CanonStateSubscriptions for RpcBlockchainProvider<P, Node, N>
890where
891    P: Provider<N> + Clone + 'static,
892    N: Network,
893    Node: NodeTypes,
894{
895    type Primitives = PrimitivesTy<Node>;
896
897    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<PrimitivesTy<Node>> {
898        trace!(target: "alloy-provider", "Subscribing to canonical state notifications");
899        self.canon_state_notification.subscribe()
900    }
901}
902
903impl<P, Node, N> ChainSpecProvider for RpcBlockchainProvider<P, Node, N>
904where
905    P: Send + Sync,
906    N: Network,
907    Node: NodeTypes,
908    Node::ChainSpec: Default,
909{
910    type ChainSpec = Node::ChainSpec;
911
912    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
913        self.chain_spec.clone()
914    }
915}
916
917/// RPC-based state provider implementation that fetches blockchain state via remote RPC calls.
918///
919/// This is the state provider counterpart to `RpcBlockchainProvider`, handling state queries
920/// at specific block heights via RPC instead of local database access.
921pub struct RpcBlockchainStateProvider<P, Node, N = alloy_network::AnyNetwork>
922where
923    Node: NodeTypes,
924{
925    /// The underlying Alloy provider
926    provider: P,
927    /// The block ID to fetch state at
928    block_id: BlockId,
929    /// Node types marker
930    node_types: std::marker::PhantomData<Node>,
931    /// Network marker
932    network: std::marker::PhantomData<N>,
933    /// Cached chain spec (shared with parent provider)
934    chain_spec: Option<Arc<Node::ChainSpec>>,
935    /// Whether to enable state root calculation
936    compute_state_root: bool,
937    /// Cached bytecode for accounts
938    ///
939    /// Since the state provider is short-lived, we don't worry about memory leaks.
940    code_store: DashMap<B256, Bytecode>,
941    /// Whether to use Reth-specific RPC methods for better performance
942    reth_rpc_support: bool,
943}
944
945impl<P: std::fmt::Debug, Node: NodeTypes, N> std::fmt::Debug
946    for RpcBlockchainStateProvider<P, Node, N>
947{
948    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
949        f.debug_struct("RpcBlockchainStateProvider")
950            .field("provider", &self.provider)
951            .field("block_id", &self.block_id)
952            .finish()
953    }
954}
955
956impl<P: Clone, Node: NodeTypes, N> RpcBlockchainStateProvider<P, Node, N> {
957    /// Creates a new state provider for the given block
958    pub fn new(
959        provider: P,
960        block_id: BlockId,
961        _primitives: std::marker::PhantomData<Node>,
962    ) -> Self {
963        Self {
964            provider,
965            block_id,
966            node_types: std::marker::PhantomData,
967            network: std::marker::PhantomData,
968            chain_spec: None,
969            compute_state_root: false,
970            code_store: Default::default(),
971            reth_rpc_support: true,
972        }
973    }
974
975    /// Creates a new state provider with a cached chain spec
976    pub fn with_chain_spec(
977        provider: P,
978        block_id: BlockId,
979        chain_spec: Arc<Node::ChainSpec>,
980    ) -> Self {
981        Self {
982            provider,
983            block_id,
984            node_types: std::marker::PhantomData,
985            network: std::marker::PhantomData,
986            chain_spec: Some(chain_spec),
987            compute_state_root: false,
988            code_store: Default::default(),
989            reth_rpc_support: true,
990        }
991    }
992
993    /// Helper function to execute async operations in a blocking context
994    fn block_on_async<F, T>(&self, fut: F) -> T
995    where
996        F: Future<Output = T>,
997    {
998        tokio::task::block_in_place(move || Handle::current().block_on(fut))
999    }
1000
1001    /// Helper function to create a new state provider with a different block ID
1002    fn with_block_id(&self, block_id: BlockId) -> Self {
1003        Self {
1004            provider: self.provider.clone(),
1005            block_id,
1006            node_types: self.node_types,
1007            network: self.network,
1008            chain_spec: self.chain_spec.clone(),
1009            compute_state_root: self.compute_state_root,
1010            code_store: Default::default(),
1011            reth_rpc_support: self.reth_rpc_support,
1012        }
1013    }
1014
1015    /// Helper function to enable state root calculation
1016    ///
1017    /// If enabled, the node will compute the state root and updates.
1018    /// When disabled, it will return zero for state root and no updates.
1019    pub const fn with_compute_state_root(mut self, is_enable: bool) -> Self {
1020        self.compute_state_root = is_enable;
1021        self
1022    }
1023
1024    /// Sets whether to use Reth-specific RPC methods for better performance
1025    ///
1026    /// If enabled, the node will use Reth's RPC methods (`debug_codeByHash` and
1027    /// `eth_getAccountInfo`) to speed up account information retrieval. When disabled, it will
1028    /// use multiple standard RPC calls to get account information.
1029    pub const fn with_reth_rpc_support(mut self, is_enable: bool) -> Self {
1030        self.reth_rpc_support = is_enable;
1031        self
1032    }
1033
1034    /// Get account information from RPC
1035    #[allow(clippy::needless_update)]
1036    fn get_account(&self, address: Address) -> Result<Option<Account>, ProviderError>
1037    where
1038        P: Provider<N> + Clone + 'static,
1039        N: Network,
1040    {
1041        // Only `eth_getAccountInfo` returns account extensions.
1042        if Account::EXTENSIONS_ENABLED && !self.reth_rpc_support {
1043            return Err(ProviderError::other(std::io::Error::other(
1044                "account extensions require an eth_getAccountInfo endpoint (reth_rpc_support)",
1045            )));
1046        }
1047
1048        let account_info = self.block_on_async(async {
1049            // Get account info in a single RPC call using `eth_getAccountInfo`
1050            if self.reth_rpc_support {
1051                return self
1052                    .provider
1053                    .get_account_info(address)
1054                    .block_id(self.block_id)
1055                    .await
1056                    .map_err(ProviderError::other);
1057            }
1058            // Get account info in multiple RPC calls
1059            let nonce = self.provider.get_transaction_count(address).block_id(self.block_id);
1060            let balance = self.provider.get_balance(address).block_id(self.block_id);
1061            let code = self.provider.get_code_at(address).block_id(self.block_id);
1062
1063            let (nonce, balance, code) = tokio::join!(nonce, balance, code,);
1064
1065            let account_info = AccountInfo {
1066                balance: balance.map_err(ProviderError::other)?,
1067                nonce: nonce.map_err(ProviderError::other)?,
1068                code: code.map_err(ProviderError::other)?,
1069                ..Default::default()
1070            };
1071
1072            let code_hash = account_info.code_hash();
1073            if code_hash != KECCAK_EMPTY {
1074                // Insert code into the cache
1075                self.code_store.insert(code_hash, Bytecode::new_raw(account_info.code.clone()));
1076            }
1077
1078            Ok(account_info)
1079        })?;
1080
1081        // Only return accounts that exist.
1082        if account_info.is_empty() {
1083            Ok(None)
1084        } else {
1085            let bytecode_hash =
1086                if account_info.code.is_empty() { None } else { Some(account_info.code_hash()) };
1087
1088            let account = Account::new(account_info.nonce, account_info.balance, bytecode_hash);
1089            #[cfg(feature = "account-ext")]
1090            let account = account.with_extension(account_info.extension);
1091            Ok(Some(account))
1092        }
1093    }
1094}
1095
1096impl<P, Node, N> StateProvider for RpcBlockchainStateProvider<P, Node, N>
1097where
1098    P: Provider<N> + Clone + 'static,
1099    N: Network,
1100    Node: NodeTypes,
1101{
1102    fn storage(
1103        &self,
1104        address: Address,
1105        storage_key: StorageKey,
1106    ) -> Result<Option<U256>, ProviderError> {
1107        self.block_on_async(async {
1108            Ok(Some(
1109                self.provider
1110                    .get_storage_at(address, storage_key.into())
1111                    .block_id(self.block_id)
1112                    .await
1113                    .map_err(ProviderError::other)?,
1114            ))
1115        })
1116    }
1117
1118    fn account_code(&self, addr: &Address) -> Result<Option<Bytecode>, ProviderError> {
1119        self.block_on_async(async {
1120            let code = self
1121                .provider
1122                .get_code_at(*addr)
1123                .block_id(self.block_id)
1124                .await
1125                .map_err(ProviderError::other)?;
1126
1127            if code.is_empty() {
1128                Ok(None)
1129            } else {
1130                Ok(Some(Bytecode::new_raw(code)))
1131            }
1132        })
1133    }
1134
1135    fn account_balance(&self, addr: &Address) -> Result<Option<U256>, ProviderError> {
1136        self.get_account(*addr).map(|acc| acc.map(|a| a.balance))
1137    }
1138
1139    fn account_nonce(&self, addr: &Address) -> Result<Option<u64>, ProviderError> {
1140        self.get_account(*addr).map(|acc| acc.map(|a| a.nonce))
1141    }
1142}
1143
1144impl<P, Node, N> BytecodeReader for RpcBlockchainStateProvider<P, Node, N>
1145where
1146    P: Provider<N> + Clone + 'static,
1147    N: Network,
1148    Node: NodeTypes,
1149{
1150    fn bytecode_by_hash(&self, code_hash: &B256) -> Result<Option<Bytecode>, ProviderError> {
1151        if !self.reth_rpc_support {
1152            return Ok(self.code_store.get(code_hash).map(|entry| entry.value().clone()));
1153        }
1154
1155        self.block_on_async(async {
1156            // The method `debug_codeByHash` is currently only available on a Reth node
1157            let code = self
1158                .provider
1159                .debug_code_by_hash(*code_hash, None)
1160                .await
1161                .map_err(ProviderError::other)?;
1162
1163            let Some(code) = code else {
1164                // If the code was not found, return None
1165                return Ok(None);
1166            };
1167
1168            Ok(Some(Bytecode::new_raw(code)))
1169        })
1170    }
1171}
1172
1173impl<P, Node, N> AccountReader for RpcBlockchainStateProvider<P, Node, N>
1174where
1175    P: Provider<N> + Clone + 'static,
1176    N: Network,
1177    Node: NodeTypes,
1178{
1179    fn basic_account(&self, address: &Address) -> Result<Option<Account>, ProviderError> {
1180        self.get_account(*address)
1181    }
1182}
1183
1184impl<P, Node, N> StateRootProvider for RpcBlockchainStateProvider<P, Node, N>
1185where
1186    P: Provider<N> + Clone + 'static,
1187    N: Network,
1188    Node: NodeTypes,
1189{
1190    fn state_root(&self, hashed_state: HashedPostState) -> Result<B256, ProviderError> {
1191        self.state_root_with_updates(hashed_state).map(|(root, _)| root)
1192    }
1193
1194    fn state_root_from_nodes(&self, _input: TrieInput) -> Result<B256, ProviderError> {
1195        warn!("state_root_from_nodes is not implemented and will return zero");
1196        Ok(B256::ZERO)
1197    }
1198
1199    fn state_root_with_updates(
1200        &self,
1201        hashed_state: HashedPostState,
1202    ) -> Result<(B256, TrieUpdates), ProviderError> {
1203        if !self.compute_state_root {
1204            return Ok((B256::ZERO, TrieUpdates::default()));
1205        }
1206
1207        self.block_on_async(async {
1208            self.provider
1209                .raw_request::<(HashedPostState, BlockId), (B256, TrieUpdates)>(
1210                    "debug_stateRootWithUpdates".into(),
1211                    (hashed_state, self.block_id),
1212                )
1213                .into_future()
1214                .await
1215                .map_err(ProviderError::other)
1216        })
1217    }
1218
1219    fn state_root_from_nodes_with_updates(
1220        &self,
1221        _input: TrieInput,
1222    ) -> Result<(B256, TrieUpdates), ProviderError> {
1223        warn!("state_root_from_nodes_with_updates is not implemented and will return zero");
1224        Ok((B256::ZERO, TrieUpdates::default()))
1225    }
1226}
1227
1228impl<P, Node, N> StorageReader for RpcBlockchainStateProvider<P, Node, N>
1229where
1230    P: Provider<N> + Clone + 'static,
1231    N: Network,
1232    Node: NodeTypes,
1233{
1234    fn plain_state_storages(
1235        &self,
1236        addresses_with_keys: impl IntoIterator<Item = (Address, impl IntoIterator<Item = StorageKey>)>,
1237    ) -> Result<Vec<(Address, Vec<reth_primitives_traits::StorageEntry>)>, ProviderError> {
1238        let mut results = Vec::new();
1239
1240        for (address, keys) in addresses_with_keys {
1241            let mut values = Vec::new();
1242            for key in keys {
1243                let value = self.storage(address, key)?.unwrap_or_default();
1244                values.push(reth_primitives_traits::StorageEntry::new(key, value));
1245            }
1246            results.push((address, values));
1247        }
1248
1249        Ok(results)
1250    }
1251
1252    fn changed_storages_with_range(
1253        &self,
1254        _range: RangeInclusive<BlockNumber>,
1255    ) -> Result<BTreeMap<Address, std::collections::BTreeSet<StorageKey>>, ProviderError> {
1256        Ok(BTreeMap::new())
1257    }
1258
1259    fn changed_storages_and_blocks_with_range(
1260        &self,
1261        _range: RangeInclusive<BlockNumber>,
1262    ) -> Result<BTreeMap<(Address, StorageKey), Vec<u64>>, ProviderError> {
1263        Ok(BTreeMap::new())
1264    }
1265}
1266
1267impl<P, Node, N> reth_storage_api::StorageRootProvider for RpcBlockchainStateProvider<P, Node, N>
1268where
1269    P: Provider<N> + Clone + 'static,
1270    N: Network,
1271    Node: NodeTypes,
1272{
1273    fn storage_root(
1274        &self,
1275        _address: Address,
1276        _hashed_storage: reth_trie::HashedStorage,
1277    ) -> Result<B256, ProviderError> {
1278        // RPC doesn't provide storage root computation
1279        Err(ProviderError::UnsupportedProvider)
1280    }
1281
1282    fn storage_proof(
1283        &self,
1284        _address: Address,
1285        _slot: B256,
1286        _hashed_storage: reth_trie::HashedStorage,
1287    ) -> Result<reth_trie::StorageProof, ProviderError> {
1288        Err(ProviderError::UnsupportedProvider)
1289    }
1290
1291    fn storage_multiproof(
1292        &self,
1293        _address: Address,
1294        _slots: &[B256],
1295        _hashed_storage: reth_trie::HashedStorage,
1296    ) -> Result<reth_trie::StorageMultiProof, ProviderError> {
1297        Err(ProviderError::UnsupportedProvider)
1298    }
1299}
1300
1301impl<P, Node, N> reth_storage_api::StateProofProvider for RpcBlockchainStateProvider<P, Node, N>
1302where
1303    P: Provider<N> + Clone + 'static,
1304    N: Network,
1305    Node: NodeTypes,
1306{
1307    fn proof(
1308        &self,
1309        _input: TrieInput,
1310        _address: Address,
1311        _slots: &[B256],
1312    ) -> Result<AccountProof, ProviderError> {
1313        Err(ProviderError::UnsupportedProvider)
1314    }
1315
1316    fn multiproof(
1317        &self,
1318        _input: TrieInput,
1319        _targets: reth_trie::MultiProofTargets,
1320    ) -> Result<MultiProof, ProviderError> {
1321        Err(ProviderError::UnsupportedProvider)
1322    }
1323
1324    fn multiproof_v2(
1325        &self,
1326        _input: TrieInput,
1327        _targets: reth_trie::MultiProofTargetsV2,
1328    ) -> Result<reth_trie::DecodedMultiProofV2, ProviderError> {
1329        Err(ProviderError::UnsupportedProvider)
1330    }
1331
1332    fn witness(
1333        &self,
1334        _input: TrieInput,
1335        _target: HashedPostState,
1336        _mode: reth_trie::ExecutionWitnessMode,
1337    ) -> Result<Vec<alloy_primitives::Bytes>, ProviderError> {
1338        Err(ProviderError::UnsupportedProvider)
1339    }
1340}
1341
1342impl<P, Node, N> reth_storage_api::HashedPostStateProvider
1343    for RpcBlockchainStateProvider<P, Node, N>
1344where
1345    P: Provider<N> + Clone + 'static,
1346    N: Network,
1347    Node: NodeTypes,
1348{
1349    fn hashed_post_state(
1350        &self,
1351        bundle_state: &revm::database::BundleState,
1352    ) -> ProviderResult<HashedPostState> {
1353        if bundle_state
1354            .state()
1355            .values()
1356            .any(|account| account.was_destroyed() && account.original_info.is_some())
1357        {
1358            return Err(ProviderError::UnsupportedProvider)
1359        }
1360        Ok(HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state()))
1361    }
1362}
1363
1364impl<P, Node, N> StateReader for RpcBlockchainStateProvider<P, Node, N>
1365where
1366    P: Provider<N> + Clone + 'static,
1367    N: Network,
1368    Node: NodeTypes,
1369{
1370    type Receipt = ReceiptTy<Node>;
1371
1372    fn get_state(
1373        &self,
1374        _block: BlockNumber,
1375    ) -> Result<Option<reth_execution_types::ExecutionOutcome<Self::Receipt>>, ProviderError> {
1376        // RPC doesn't provide execution outcomes
1377        Err(ProviderError::UnsupportedProvider)
1378    }
1379}
1380
1381impl<P, Node, N> DbTxProvider for RpcBlockchainStateProvider<P, Node, N>
1382where
1383    P: Provider<N> + Clone + 'static,
1384    N: Network,
1385    Node: NodeTypes,
1386{
1387    type Tx = TxMock;
1388
1389    fn tx(&self) -> &Self::Tx {
1390        // We can't use a static here since TxMock doesn't allow direct construction
1391        // This is fine since we're just returning a mock transaction
1392        unimplemented!("tx not supported for RPC provider")
1393    }
1394}
1395
1396impl<P, Node, N> DBProvider for RpcBlockchainStateProvider<P, Node, N>
1397where
1398    P: Provider<N> + Clone + 'static,
1399    N: Network,
1400    Node: NodeTypes,
1401{
1402    fn tx_mut(&mut self) -> &mut Self::Tx {
1403        unimplemented!("tx_mut not supported for RPC provider")
1404    }
1405
1406    fn into_tx(self) -> Self::Tx {
1407        TxMock::default()
1408    }
1409
1410    fn disable_long_read_transaction_safety(self) -> Self {
1411        // No-op for RPC provider
1412        self
1413    }
1414
1415    fn commit(self) -> ProviderResult<()> {
1416        unimplemented!("commit not supported for RPC provider")
1417    }
1418
1419    fn prune_modes_ref(&self) -> &reth_prune_types::PruneModes {
1420        unimplemented!("prune modes not supported for RPC provider")
1421    }
1422}
1423
1424impl<P, Node, N> BlockNumReader for RpcBlockchainStateProvider<P, Node, N>
1425where
1426    P: Provider<N> + Clone + 'static,
1427    N: Network,
1428    Node: NodeTypes,
1429{
1430    fn chain_info(&self) -> Result<ChainInfo, ProviderError> {
1431        self.block_on_async(async {
1432            let block = self
1433                .provider
1434                .get_block(self.block_id)
1435                .await
1436                .map_err(ProviderError::other)?
1437                .ok_or(ProviderError::HeaderNotFound(0.into()))?;
1438
1439            Ok(ChainInfo { best_hash: block.header().hash(), best_number: block.header().number() })
1440        })
1441    }
1442
1443    fn best_block_number(&self) -> Result<BlockNumber, ProviderError> {
1444        self.block_on_async(async {
1445            self.provider.get_block_number().await.map_err(ProviderError::other)
1446        })
1447    }
1448
1449    fn last_block_number(&self) -> Result<BlockNumber, ProviderError> {
1450        self.best_block_number()
1451    }
1452
1453    fn block_number(&self, hash: B256) -> Result<Option<BlockNumber>, ProviderError> {
1454        self.block_on_async(async {
1455            let block =
1456                self.provider.get_block_by_hash(hash).await.map_err(ProviderError::other)?;
1457
1458            Ok(block.map(|b| b.header().number()))
1459        })
1460    }
1461}
1462
1463impl<P, Node, N> BlockHashReader for RpcBlockchainStateProvider<P, Node, N>
1464where
1465    P: Provider<N> + Clone + 'static,
1466    N: Network,
1467    Node: NodeTypes,
1468{
1469    fn block_hash(&self, number: u64) -> Result<Option<B256>, ProviderError> {
1470        self.block_on_async(async {
1471            let block = self
1472                .provider
1473                .get_block_by_number(number.into())
1474                .await
1475                .map_err(ProviderError::other)?;
1476
1477            Ok(block.map(|b| b.header().hash()))
1478        })
1479    }
1480
1481    fn canonical_hashes_range(
1482        &self,
1483        _start: BlockNumber,
1484        _end: BlockNumber,
1485    ) -> Result<Vec<B256>, ProviderError> {
1486        Err(ProviderError::UnsupportedProvider)
1487    }
1488}
1489
1490impl<P, Node, N> BlockIdReader for RpcBlockchainStateProvider<P, Node, N>
1491where
1492    P: Provider<N> + Clone + 'static,
1493    N: Network,
1494    Node: NodeTypes,
1495{
1496    fn block_number_for_id(
1497        &self,
1498        _block_id: BlockId,
1499    ) -> Result<Option<BlockNumber>, ProviderError> {
1500        Err(ProviderError::UnsupportedProvider)
1501    }
1502
1503    fn pending_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1504        Err(ProviderError::UnsupportedProvider)
1505    }
1506
1507    fn safe_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1508        Err(ProviderError::UnsupportedProvider)
1509    }
1510
1511    fn finalized_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1512        Err(ProviderError::UnsupportedProvider)
1513    }
1514}
1515
1516impl<P, Node, N> BlockReader for RpcBlockchainStateProvider<P, Node, N>
1517where
1518    P: Provider<N> + Clone + 'static,
1519    N: Network,
1520    Node: NodeTypes,
1521{
1522    type Block = BlockTy<Node>;
1523
1524    fn find_block_by_hash(
1525        &self,
1526        _hash: B256,
1527        _source: reth_provider::BlockSource,
1528    ) -> Result<Option<Self::Block>, ProviderError> {
1529        Err(ProviderError::UnsupportedProvider)
1530    }
1531
1532    fn block(
1533        &self,
1534        _id: alloy_rpc_types::BlockHashOrNumber,
1535    ) -> Result<Option<Self::Block>, ProviderError> {
1536        Err(ProviderError::UnsupportedProvider)
1537    }
1538
1539    fn pending_block(&self) -> Result<Option<Arc<RecoveredBlock<Self::Block>>>, ProviderError> {
1540        Err(ProviderError::UnsupportedProvider)
1541    }
1542
1543    fn pending_block_and_receipts(
1544        &self,
1545    ) -> Result<Option<RecoveredBlockAndExecutionOutput<Self::Block, Self::Receipt>>, ProviderError>
1546    {
1547        Err(ProviderError::UnsupportedProvider)
1548    }
1549
1550    fn recovered_block(
1551        &self,
1552        _id: alloy_rpc_types::BlockHashOrNumber,
1553        _transaction_kind: TransactionVariant,
1554    ) -> Result<Option<RecoveredBlock<Self::Block>>, ProviderError> {
1555        Err(ProviderError::UnsupportedProvider)
1556    }
1557
1558    fn sealed_block_with_senders(
1559        &self,
1560        _id: alloy_rpc_types::BlockHashOrNumber,
1561        _transaction_kind: TransactionVariant,
1562    ) -> Result<Option<RecoveredBlock<BlockTy<Node>>>, ProviderError> {
1563        Err(ProviderError::UnsupportedProvider)
1564    }
1565
1566    fn block_range(
1567        &self,
1568        _range: RangeInclusive<BlockNumber>,
1569    ) -> Result<Vec<Self::Block>, ProviderError> {
1570        Err(ProviderError::UnsupportedProvider)
1571    }
1572
1573    fn block_with_senders_range(
1574        &self,
1575        _range: RangeInclusive<BlockNumber>,
1576    ) -> Result<Vec<RecoveredBlock<BlockTy<Node>>>, ProviderError> {
1577        Err(ProviderError::UnsupportedProvider)
1578    }
1579
1580    fn recovered_block_range(
1581        &self,
1582        _range: RangeInclusive<BlockNumber>,
1583    ) -> Result<Vec<RecoveredBlock<Self::Block>>, ProviderError> {
1584        Err(ProviderError::UnsupportedProvider)
1585    }
1586
1587    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
1588        Err(ProviderError::UnsupportedProvider)
1589    }
1590}
1591
1592impl<P, Node, N> TransactionsProvider for RpcBlockchainStateProvider<P, Node, N>
1593where
1594    P: Provider<N> + Clone + 'static,
1595    N: Network,
1596    Node: NodeTypes,
1597{
1598    type Transaction = TxTy<Node>;
1599
1600    fn transaction_id(&self, _tx_hash: B256) -> Result<Option<TxNumber>, ProviderError> {
1601        Err(ProviderError::UnsupportedProvider)
1602    }
1603
1604    fn transaction_by_id(&self, _id: TxNumber) -> Result<Option<Self::Transaction>, ProviderError> {
1605        Err(ProviderError::UnsupportedProvider)
1606    }
1607
1608    fn transaction_by_id_unhashed(
1609        &self,
1610        _id: TxNumber,
1611    ) -> Result<Option<Self::Transaction>, ProviderError> {
1612        Err(ProviderError::UnsupportedProvider)
1613    }
1614
1615    fn transaction_by_hash(&self, _hash: B256) -> Result<Option<Self::Transaction>, ProviderError> {
1616        Err(ProviderError::UnsupportedProvider)
1617    }
1618
1619    fn transaction_by_hash_with_meta(
1620        &self,
1621        _hash: B256,
1622    ) -> Result<Option<(Self::Transaction, TransactionMeta)>, ProviderError> {
1623        Err(ProviderError::UnsupportedProvider)
1624    }
1625
1626    fn transactions_by_block(
1627        &self,
1628        _block: alloy_rpc_types::BlockHashOrNumber,
1629    ) -> Result<Option<Vec<Self::Transaction>>, ProviderError> {
1630        Err(ProviderError::UnsupportedProvider)
1631    }
1632
1633    fn transactions_by_block_range(
1634        &self,
1635        _range: impl RangeBounds<BlockNumber>,
1636    ) -> Result<Vec<Vec<Self::Transaction>>, ProviderError> {
1637        Err(ProviderError::UnsupportedProvider)
1638    }
1639
1640    fn transactions_by_tx_range(
1641        &self,
1642        _range: impl RangeBounds<TxNumber>,
1643    ) -> Result<Vec<Self::Transaction>, ProviderError> {
1644        Err(ProviderError::UnsupportedProvider)
1645    }
1646
1647    fn senders_by_tx_range(
1648        &self,
1649        _range: impl RangeBounds<TxNumber>,
1650    ) -> Result<Vec<Address>, ProviderError> {
1651        Err(ProviderError::UnsupportedProvider)
1652    }
1653
1654    fn transaction_sender(&self, _id: TxNumber) -> Result<Option<Address>, ProviderError> {
1655        Err(ProviderError::UnsupportedProvider)
1656    }
1657}
1658
1659impl<P, Node, N> ReceiptProvider for RpcBlockchainStateProvider<P, Node, N>
1660where
1661    P: Provider<N> + Clone + 'static,
1662    N: Network,
1663    Node: NodeTypes,
1664{
1665    type Receipt = ReceiptTy<Node>;
1666
1667    fn receipt(&self, _id: TxNumber) -> Result<Option<Self::Receipt>, ProviderError> {
1668        Err(ProviderError::UnsupportedProvider)
1669    }
1670
1671    fn receipt_by_hash(&self, _hash: B256) -> Result<Option<Self::Receipt>, ProviderError> {
1672        Err(ProviderError::UnsupportedProvider)
1673    }
1674
1675    fn receipts_by_block(
1676        &self,
1677        _block: alloy_rpc_types::BlockHashOrNumber,
1678    ) -> Result<Option<Vec<Self::Receipt>>, ProviderError> {
1679        Err(ProviderError::UnsupportedProvider)
1680    }
1681
1682    fn receipts_by_tx_range(
1683        &self,
1684        _range: impl RangeBounds<TxNumber>,
1685    ) -> Result<Vec<Self::Receipt>, ProviderError> {
1686        Err(ProviderError::UnsupportedProvider)
1687    }
1688
1689    fn receipts_by_block_range(
1690        &self,
1691        _range: RangeInclusive<BlockNumber>,
1692    ) -> Result<Vec<Vec<Self::Receipt>>, ProviderError> {
1693        Err(ProviderError::UnsupportedProvider)
1694    }
1695}
1696
1697impl<P, Node, N> HeaderProvider for RpcBlockchainStateProvider<P, Node, N>
1698where
1699    P: Provider<N> + Clone + 'static,
1700    N: Network,
1701    Node: NodeTypes,
1702{
1703    type Header = HeaderTy<Node>;
1704
1705    fn header(&self, _block_hash: BlockHash) -> Result<Option<Self::Header>, ProviderError> {
1706        Err(ProviderError::UnsupportedProvider)
1707    }
1708
1709    fn header_by_number(&self, _num: BlockNumber) -> Result<Option<Self::Header>, ProviderError> {
1710        Err(ProviderError::UnsupportedProvider)
1711    }
1712
1713    fn headers_range(
1714        &self,
1715        _range: impl RangeBounds<BlockNumber>,
1716    ) -> Result<Vec<Self::Header>, ProviderError> {
1717        Err(ProviderError::UnsupportedProvider)
1718    }
1719
1720    fn sealed_header(
1721        &self,
1722        _number: BlockNumber,
1723    ) -> Result<Option<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1724        Err(ProviderError::UnsupportedProvider)
1725    }
1726
1727    fn sealed_headers_range(
1728        &self,
1729        _range: impl RangeBounds<BlockNumber>,
1730    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1731        Err(ProviderError::UnsupportedProvider)
1732    }
1733
1734    fn sealed_headers_while(
1735        &self,
1736        _range: impl RangeBounds<BlockNumber>,
1737        _predicate: impl FnMut(&SealedHeader<HeaderTy<Node>>) -> bool,
1738    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1739        Err(ProviderError::UnsupportedProvider)
1740    }
1741}
1742
1743impl<P, Node, N> PruneCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1744where
1745    P: Provider<N> + Clone + 'static,
1746    N: Network,
1747    Node: NodeTypes,
1748{
1749    fn get_prune_checkpoint(
1750        &self,
1751        _segment: PruneSegment,
1752    ) -> Result<Option<PruneCheckpoint>, ProviderError> {
1753        Err(ProviderError::UnsupportedProvider)
1754    }
1755
1756    fn get_prune_checkpoints(&self) -> Result<Vec<(PruneSegment, PruneCheckpoint)>, ProviderError> {
1757        Err(ProviderError::UnsupportedProvider)
1758    }
1759}
1760
1761impl<P, Node, N> StageCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1762where
1763    P: Provider<N> + Clone + 'static,
1764    N: Network,
1765    Node: NodeTypes,
1766{
1767    fn get_stage_checkpoint(&self, _id: StageId) -> Result<Option<StageCheckpoint>, ProviderError> {
1768        Err(ProviderError::UnsupportedProvider)
1769    }
1770
1771    fn get_stage_checkpoint_progress(
1772        &self,
1773        _id: StageId,
1774    ) -> Result<Option<Vec<u8>>, ProviderError> {
1775        Err(ProviderError::UnsupportedProvider)
1776    }
1777
1778    fn get_all_checkpoints(&self) -> Result<Vec<(String, StageCheckpoint)>, ProviderError> {
1779        Err(ProviderError::UnsupportedProvider)
1780    }
1781}
1782
1783impl<P, Node, N> ChangeSetReader for RpcBlockchainStateProvider<P, Node, N>
1784where
1785    P: Provider<N> + Clone + 'static,
1786    N: Network,
1787    Node: NodeTypes,
1788{
1789    fn account_block_changeset(
1790        &self,
1791        _block_number: BlockNumber,
1792    ) -> Result<Vec<reth_db_api::models::AccountBeforeTx>, ProviderError> {
1793        Err(ProviderError::UnsupportedProvider)
1794    }
1795
1796    fn get_account_before_block(
1797        &self,
1798        _block_number: BlockNumber,
1799        _address: Address,
1800    ) -> ProviderResult<Option<reth_db_api::models::AccountBeforeTx>> {
1801        Err(ProviderError::UnsupportedProvider)
1802    }
1803
1804    fn account_changesets_range(
1805        &self,
1806        _range: impl std::ops::RangeBounds<BlockNumber>,
1807    ) -> ProviderResult<Vec<(BlockNumber, reth_db_api::models::AccountBeforeTx)>> {
1808        Err(ProviderError::UnsupportedProvider)
1809    }
1810}
1811
1812impl<P, Node, N> StateProviderFactory for RpcBlockchainStateProvider<P, Node, N>
1813where
1814    P: Provider<N> + Clone + 'static + Send + Sync,
1815    Node: NodeTypes + 'static,
1816    Node::ChainSpec: Send + Sync,
1817    N: Network,
1818    Self: Clone + 'static,
1819{
1820    type Primitives = PrimitivesTy<Node>;
1821
1822    fn latest(&self) -> Result<StateProviderBox, ProviderError> {
1823        Ok(Box::new(self.with_block_id(self.best_block_number()?.into())))
1824    }
1825
1826    fn state_with_block_appended(
1827        &self,
1828        _parent_hash: BlockHash,
1829        _block: ExecutedBlock<PrimitivesTy<Node>>,
1830    ) -> ProviderResult<StateProviderBox> {
1831        Err(ProviderError::UnsupportedProvider)
1832    }
1833
1834    fn state_by_block_id(&self, block_id: BlockId) -> Result<StateProviderBox, ProviderError> {
1835        Ok(Box::new(self.with_block_id(block_id)))
1836    }
1837
1838    fn state_by_block_number_or_tag(
1839        &self,
1840        number_or_tag: alloy_rpc_types::BlockNumberOrTag,
1841    ) -> Result<StateProviderBox, ProviderError> {
1842        match number_or_tag {
1843            alloy_rpc_types::BlockNumberOrTag::Latest => self.latest(),
1844            alloy_rpc_types::BlockNumberOrTag::Pending => self.pending(),
1845            alloy_rpc_types::BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1846            _ => Err(ProviderError::UnsupportedProvider),
1847        }
1848    }
1849
1850    fn history_by_block_number(
1851        &self,
1852        block_number: BlockNumber,
1853    ) -> Result<StateProviderBox, ProviderError> {
1854        Ok(Box::new(Self::new(
1855            self.provider.clone(),
1856            BlockId::number(block_number),
1857            self.node_types,
1858        )))
1859    }
1860
1861    fn history_by_block_hash(
1862        &self,
1863        block_hash: BlockHash,
1864    ) -> Result<StateProviderBox, ProviderError> {
1865        Ok(Box::new(self.with_block_id(BlockId::hash(block_hash))))
1866    }
1867
1868    fn state_by_block_hash(
1869        &self,
1870        block_hash: BlockHash,
1871    ) -> Result<StateProviderBox, ProviderError> {
1872        self.history_by_block_hash(block_hash)
1873    }
1874
1875    fn pending(&self) -> Result<StateProviderBox, ProviderError> {
1876        Ok(Box::new(self.clone()))
1877    }
1878
1879    fn pending_state_by_hash(
1880        &self,
1881        _block_hash: B256,
1882    ) -> Result<Option<StateProviderBox>, ProviderError> {
1883        // RPC provider doesn't support pending state by hash
1884        Err(ProviderError::UnsupportedProvider)
1885    }
1886
1887    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1888        Ok(None)
1889    }
1890}
1891
1892impl<P, Node, N> ChainSpecProvider for RpcBlockchainStateProvider<P, Node, N>
1893where
1894    P: Send + Sync + std::fmt::Debug,
1895    N: Network,
1896    Node: NodeTypes,
1897    Node::ChainSpec: Default,
1898{
1899    type ChainSpec = Node::ChainSpec;
1900
1901    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
1902        if let Some(chain_spec) = &self.chain_spec {
1903            chain_spec.clone()
1904        } else {
1905            // Fallback for when chain_spec is not provided
1906            Arc::new(Node::ChainSpec::default())
1907        }
1908    }
1909}
1910
1911// Note: FullExecutionDataProvider is already implemented via the blanket implementation
1912// for types that implement both ExecutionDataProvider and BlockExecutionForkProvider
1913
1914impl<P, Node, N> StatsReader for RpcBlockchainStateProvider<P, Node, N>
1915where
1916    P: Provider<N> + Clone + 'static,
1917    N: Network,
1918    Node: NodeTypes,
1919{
1920    fn count_entries<T: reth_db_api::table::Table>(&self) -> Result<usize, ProviderError> {
1921        Ok(0)
1922    }
1923}
1924
1925impl<P, Node, N> BlockBodyIndicesProvider for RpcBlockchainStateProvider<P, Node, N>
1926where
1927    P: Provider<N> + Clone + 'static,
1928    N: Network,
1929    Node: NodeTypes,
1930{
1931    fn block_body_indices(
1932        &self,
1933        _num: u64,
1934    ) -> Result<Option<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1935        Err(ProviderError::UnsupportedProvider)
1936    }
1937
1938    fn block_body_indices_range(
1939        &self,
1940        _range: RangeInclusive<u64>,
1941    ) -> Result<Vec<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1942        Err(ProviderError::UnsupportedProvider)
1943    }
1944}
1945
1946impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainStateProvider<P, Node, N>
1947where
1948    P: Send + Sync + std::fmt::Debug,
1949    N: Network,
1950    Node: NodeTypes,
1951{
1952    type Primitives = PrimitivesTy<Node>;
1953}
1954
1955impl<P, Node, N> ChainStateBlockReader for RpcBlockchainStateProvider<P, Node, N>
1956where
1957    P: Provider<N> + Clone + 'static,
1958    N: Network,
1959    Node: NodeTypes,
1960{
1961    fn last_finalized_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1962        Err(ProviderError::UnsupportedProvider)
1963    }
1964
1965    fn last_safe_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1966        Err(ProviderError::UnsupportedProvider)
1967    }
1968}
1969
1970impl<P, Node, N> ChainStateBlockWriter for RpcBlockchainStateProvider<P, Node, N>
1971where
1972    P: Provider<N> + Clone + 'static,
1973    N: Network,
1974    Node: NodeTypes,
1975{
1976    fn save_finalized_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1977        Err(ProviderError::UnsupportedProvider)
1978    }
1979
1980    fn save_safe_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1981        Err(ProviderError::UnsupportedProvider)
1982    }
1983}