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