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