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        _mode: reth_trie::ExecutionWitnessMode,
1307    ) -> Result<Vec<alloy_primitives::Bytes>, ProviderError> {
1308        Err(ProviderError::UnsupportedProvider)
1309    }
1310}
1311
1312impl<P, Node, N> reth_storage_api::HashedPostStateProvider
1313    for RpcBlockchainStateProvider<P, Node, N>
1314where
1315    P: Provider<N> + Clone + 'static,
1316    N: Network,
1317    Node: NodeTypes,
1318{
1319    fn hashed_post_state(&self, bundle_state: &revm::database::BundleState) -> HashedPostState {
1320        HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
1321    }
1322}
1323
1324impl<P, Node, N> StateReader for RpcBlockchainStateProvider<P, Node, N>
1325where
1326    P: Provider<N> + Clone + 'static,
1327    N: Network,
1328    Node: NodeTypes,
1329{
1330    type Receipt = ReceiptTy<Node>;
1331
1332    fn get_state(
1333        &self,
1334        _block: BlockNumber,
1335    ) -> Result<Option<reth_execution_types::ExecutionOutcome<Self::Receipt>>, ProviderError> {
1336        // RPC doesn't provide execution outcomes
1337        Err(ProviderError::UnsupportedProvider)
1338    }
1339}
1340
1341impl<P, Node, N> DBProvider for RpcBlockchainStateProvider<P, Node, N>
1342where
1343    P: Provider<N> + Clone + 'static,
1344    N: Network,
1345    Node: NodeTypes,
1346{
1347    type Tx = TxMock;
1348
1349    fn tx_ref(&self) -> &Self::Tx {
1350        // We can't use a static here since TxMock doesn't allow direct construction
1351        // This is fine since we're just returning a mock transaction
1352        unimplemented!("tx_ref not supported for RPC provider")
1353    }
1354
1355    fn tx_mut(&mut self) -> &mut Self::Tx {
1356        unimplemented!("tx_mut not supported for RPC provider")
1357    }
1358
1359    fn into_tx(self) -> Self::Tx {
1360        TxMock::default()
1361    }
1362
1363    fn disable_long_read_transaction_safety(self) -> Self {
1364        // No-op for RPC provider
1365        self
1366    }
1367
1368    fn commit(self) -> ProviderResult<()> {
1369        unimplemented!("commit not supported for RPC provider")
1370    }
1371
1372    fn prune_modes_ref(&self) -> &reth_prune_types::PruneModes {
1373        unimplemented!("prune modes not supported for RPC provider")
1374    }
1375}
1376
1377impl<P, Node, N> BlockNumReader for RpcBlockchainStateProvider<P, Node, N>
1378where
1379    P: Provider<N> + Clone + 'static,
1380    N: Network,
1381    Node: NodeTypes,
1382{
1383    fn chain_info(&self) -> Result<ChainInfo, ProviderError> {
1384        self.block_on_async(async {
1385            let block = self
1386                .provider
1387                .get_block(self.block_id)
1388                .await
1389                .map_err(ProviderError::other)?
1390                .ok_or(ProviderError::HeaderNotFound(0.into()))?;
1391
1392            Ok(ChainInfo { best_hash: block.header().hash(), best_number: block.header().number() })
1393        })
1394    }
1395
1396    fn best_block_number(&self) -> Result<BlockNumber, ProviderError> {
1397        self.block_on_async(async {
1398            self.provider.get_block_number().await.map_err(ProviderError::other)
1399        })
1400    }
1401
1402    fn last_block_number(&self) -> Result<BlockNumber, ProviderError> {
1403        self.best_block_number()
1404    }
1405
1406    fn block_number(&self, hash: B256) -> Result<Option<BlockNumber>, ProviderError> {
1407        self.block_on_async(async {
1408            let block =
1409                self.provider.get_block_by_hash(hash).await.map_err(ProviderError::other)?;
1410
1411            Ok(block.map(|b| b.header().number()))
1412        })
1413    }
1414}
1415
1416impl<P, Node, N> BlockHashReader for RpcBlockchainStateProvider<P, Node, N>
1417where
1418    P: Provider<N> + Clone + 'static,
1419    N: Network,
1420    Node: NodeTypes,
1421{
1422    fn block_hash(&self, number: u64) -> Result<Option<B256>, ProviderError> {
1423        self.block_on_async(async {
1424            let block = self
1425                .provider
1426                .get_block_by_number(number.into())
1427                .await
1428                .map_err(ProviderError::other)?;
1429
1430            Ok(block.map(|b| b.header().hash()))
1431        })
1432    }
1433
1434    fn canonical_hashes_range(
1435        &self,
1436        _start: BlockNumber,
1437        _end: BlockNumber,
1438    ) -> Result<Vec<B256>, ProviderError> {
1439        Err(ProviderError::UnsupportedProvider)
1440    }
1441}
1442
1443impl<P, Node, N> BlockIdReader for RpcBlockchainStateProvider<P, Node, N>
1444where
1445    P: Provider<N> + Clone + 'static,
1446    N: Network,
1447    Node: NodeTypes,
1448{
1449    fn block_number_for_id(
1450        &self,
1451        _block_id: BlockId,
1452    ) -> Result<Option<BlockNumber>, ProviderError> {
1453        Err(ProviderError::UnsupportedProvider)
1454    }
1455
1456    fn pending_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1457        Err(ProviderError::UnsupportedProvider)
1458    }
1459
1460    fn safe_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1461        Err(ProviderError::UnsupportedProvider)
1462    }
1463
1464    fn finalized_block_num_hash(&self) -> Result<Option<alloy_eips::BlockNumHash>, ProviderError> {
1465        Err(ProviderError::UnsupportedProvider)
1466    }
1467}
1468
1469impl<P, Node, N> BlockReader for RpcBlockchainStateProvider<P, Node, N>
1470where
1471    P: Provider<N> + Clone + 'static,
1472    N: Network,
1473    Node: NodeTypes,
1474{
1475    type Block = BlockTy<Node>;
1476
1477    fn find_block_by_hash(
1478        &self,
1479        _hash: B256,
1480        _source: reth_provider::BlockSource,
1481    ) -> Result<Option<Self::Block>, ProviderError> {
1482        Err(ProviderError::UnsupportedProvider)
1483    }
1484
1485    fn block(
1486        &self,
1487        _id: alloy_rpc_types::BlockHashOrNumber,
1488    ) -> Result<Option<Self::Block>, ProviderError> {
1489        Err(ProviderError::UnsupportedProvider)
1490    }
1491
1492    fn pending_block(&self) -> Result<Option<RecoveredBlock<Self::Block>>, ProviderError> {
1493        Err(ProviderError::UnsupportedProvider)
1494    }
1495
1496    fn pending_block_and_receipts(
1497        &self,
1498    ) -> Result<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>, ProviderError> {
1499        Err(ProviderError::UnsupportedProvider)
1500    }
1501
1502    fn recovered_block(
1503        &self,
1504        _id: alloy_rpc_types::BlockHashOrNumber,
1505        _transaction_kind: TransactionVariant,
1506    ) -> Result<Option<RecoveredBlock<Self::Block>>, ProviderError> {
1507        Err(ProviderError::UnsupportedProvider)
1508    }
1509
1510    fn sealed_block_with_senders(
1511        &self,
1512        _id: alloy_rpc_types::BlockHashOrNumber,
1513        _transaction_kind: TransactionVariant,
1514    ) -> Result<Option<RecoveredBlock<BlockTy<Node>>>, ProviderError> {
1515        Err(ProviderError::UnsupportedProvider)
1516    }
1517
1518    fn block_range(
1519        &self,
1520        _range: RangeInclusive<BlockNumber>,
1521    ) -> Result<Vec<Self::Block>, ProviderError> {
1522        Err(ProviderError::UnsupportedProvider)
1523    }
1524
1525    fn block_with_senders_range(
1526        &self,
1527        _range: RangeInclusive<BlockNumber>,
1528    ) -> Result<Vec<RecoveredBlock<BlockTy<Node>>>, ProviderError> {
1529        Err(ProviderError::UnsupportedProvider)
1530    }
1531
1532    fn recovered_block_range(
1533        &self,
1534        _range: RangeInclusive<BlockNumber>,
1535    ) -> Result<Vec<RecoveredBlock<Self::Block>>, ProviderError> {
1536        Err(ProviderError::UnsupportedProvider)
1537    }
1538
1539    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
1540        Err(ProviderError::UnsupportedProvider)
1541    }
1542}
1543
1544impl<P, Node, N> TransactionsProvider for RpcBlockchainStateProvider<P, Node, N>
1545where
1546    P: Provider<N> + Clone + 'static,
1547    N: Network,
1548    Node: NodeTypes,
1549{
1550    type Transaction = TxTy<Node>;
1551
1552    fn transaction_id(&self, _tx_hash: B256) -> Result<Option<TxNumber>, ProviderError> {
1553        Err(ProviderError::UnsupportedProvider)
1554    }
1555
1556    fn transaction_by_id(&self, _id: TxNumber) -> Result<Option<Self::Transaction>, ProviderError> {
1557        Err(ProviderError::UnsupportedProvider)
1558    }
1559
1560    fn transaction_by_id_unhashed(
1561        &self,
1562        _id: TxNumber,
1563    ) -> Result<Option<Self::Transaction>, ProviderError> {
1564        Err(ProviderError::UnsupportedProvider)
1565    }
1566
1567    fn transaction_by_hash(&self, _hash: B256) -> Result<Option<Self::Transaction>, ProviderError> {
1568        Err(ProviderError::UnsupportedProvider)
1569    }
1570
1571    fn transaction_by_hash_with_meta(
1572        &self,
1573        _hash: B256,
1574    ) -> Result<Option<(Self::Transaction, TransactionMeta)>, ProviderError> {
1575        Err(ProviderError::UnsupportedProvider)
1576    }
1577
1578    fn transactions_by_block(
1579        &self,
1580        _block: alloy_rpc_types::BlockHashOrNumber,
1581    ) -> Result<Option<Vec<Self::Transaction>>, ProviderError> {
1582        Err(ProviderError::UnsupportedProvider)
1583    }
1584
1585    fn transactions_by_block_range(
1586        &self,
1587        _range: impl RangeBounds<BlockNumber>,
1588    ) -> Result<Vec<Vec<Self::Transaction>>, ProviderError> {
1589        Err(ProviderError::UnsupportedProvider)
1590    }
1591
1592    fn transactions_by_tx_range(
1593        &self,
1594        _range: impl RangeBounds<TxNumber>,
1595    ) -> Result<Vec<Self::Transaction>, ProviderError> {
1596        Err(ProviderError::UnsupportedProvider)
1597    }
1598
1599    fn senders_by_tx_range(
1600        &self,
1601        _range: impl RangeBounds<TxNumber>,
1602    ) -> Result<Vec<Address>, ProviderError> {
1603        Err(ProviderError::UnsupportedProvider)
1604    }
1605
1606    fn transaction_sender(&self, _id: TxNumber) -> Result<Option<Address>, ProviderError> {
1607        Err(ProviderError::UnsupportedProvider)
1608    }
1609}
1610
1611impl<P, Node, N> ReceiptProvider for RpcBlockchainStateProvider<P, Node, N>
1612where
1613    P: Provider<N> + Clone + 'static,
1614    N: Network,
1615    Node: NodeTypes,
1616{
1617    type Receipt = ReceiptTy<Node>;
1618
1619    fn receipt(&self, _id: TxNumber) -> Result<Option<Self::Receipt>, ProviderError> {
1620        Err(ProviderError::UnsupportedProvider)
1621    }
1622
1623    fn receipt_by_hash(&self, _hash: B256) -> Result<Option<Self::Receipt>, ProviderError> {
1624        Err(ProviderError::UnsupportedProvider)
1625    }
1626
1627    fn receipts_by_block(
1628        &self,
1629        _block: alloy_rpc_types::BlockHashOrNumber,
1630    ) -> Result<Option<Vec<Self::Receipt>>, ProviderError> {
1631        Err(ProviderError::UnsupportedProvider)
1632    }
1633
1634    fn receipts_by_tx_range(
1635        &self,
1636        _range: impl RangeBounds<TxNumber>,
1637    ) -> Result<Vec<Self::Receipt>, ProviderError> {
1638        Err(ProviderError::UnsupportedProvider)
1639    }
1640
1641    fn receipts_by_block_range(
1642        &self,
1643        _range: RangeInclusive<BlockNumber>,
1644    ) -> Result<Vec<Vec<Self::Receipt>>, ProviderError> {
1645        Err(ProviderError::UnsupportedProvider)
1646    }
1647}
1648
1649impl<P, Node, N> HeaderProvider for RpcBlockchainStateProvider<P, Node, N>
1650where
1651    P: Provider<N> + Clone + 'static,
1652    N: Network,
1653    Node: NodeTypes,
1654{
1655    type Header = HeaderTy<Node>;
1656
1657    fn header(&self, _block_hash: BlockHash) -> Result<Option<Self::Header>, ProviderError> {
1658        Err(ProviderError::UnsupportedProvider)
1659    }
1660
1661    fn header_by_number(&self, _num: BlockNumber) -> Result<Option<Self::Header>, ProviderError> {
1662        Err(ProviderError::UnsupportedProvider)
1663    }
1664
1665    fn headers_range(
1666        &self,
1667        _range: impl RangeBounds<BlockNumber>,
1668    ) -> Result<Vec<Self::Header>, ProviderError> {
1669        Err(ProviderError::UnsupportedProvider)
1670    }
1671
1672    fn sealed_header(
1673        &self,
1674        _number: BlockNumber,
1675    ) -> Result<Option<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1676        Err(ProviderError::UnsupportedProvider)
1677    }
1678
1679    fn sealed_headers_range(
1680        &self,
1681        _range: impl RangeBounds<BlockNumber>,
1682    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1683        Err(ProviderError::UnsupportedProvider)
1684    }
1685
1686    fn sealed_headers_while(
1687        &self,
1688        _range: impl RangeBounds<BlockNumber>,
1689        _predicate: impl FnMut(&SealedHeader<HeaderTy<Node>>) -> bool,
1690    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1691        Err(ProviderError::UnsupportedProvider)
1692    }
1693}
1694
1695impl<P, Node, N> PruneCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1696where
1697    P: Provider<N> + Clone + 'static,
1698    N: Network,
1699    Node: NodeTypes,
1700{
1701    fn get_prune_checkpoint(
1702        &self,
1703        _segment: PruneSegment,
1704    ) -> Result<Option<PruneCheckpoint>, ProviderError> {
1705        Err(ProviderError::UnsupportedProvider)
1706    }
1707
1708    fn get_prune_checkpoints(&self) -> Result<Vec<(PruneSegment, PruneCheckpoint)>, ProviderError> {
1709        Err(ProviderError::UnsupportedProvider)
1710    }
1711}
1712
1713impl<P, Node, N> StageCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1714where
1715    P: Provider<N> + Clone + 'static,
1716    N: Network,
1717    Node: NodeTypes,
1718{
1719    fn get_stage_checkpoint(&self, _id: StageId) -> Result<Option<StageCheckpoint>, ProviderError> {
1720        Err(ProviderError::UnsupportedProvider)
1721    }
1722
1723    fn get_stage_checkpoint_progress(
1724        &self,
1725        _id: StageId,
1726    ) -> Result<Option<Vec<u8>>, ProviderError> {
1727        Err(ProviderError::UnsupportedProvider)
1728    }
1729
1730    fn get_all_checkpoints(&self) -> Result<Vec<(String, StageCheckpoint)>, ProviderError> {
1731        Err(ProviderError::UnsupportedProvider)
1732    }
1733}
1734
1735impl<P, Node, N> ChangeSetReader for RpcBlockchainStateProvider<P, Node, N>
1736where
1737    P: Provider<N> + Clone + 'static,
1738    N: Network,
1739    Node: NodeTypes,
1740{
1741    fn account_block_changeset(
1742        &self,
1743        _block_number: BlockNumber,
1744    ) -> Result<Vec<reth_db_api::models::AccountBeforeTx>, ProviderError> {
1745        Err(ProviderError::UnsupportedProvider)
1746    }
1747
1748    fn get_account_before_block(
1749        &self,
1750        _block_number: BlockNumber,
1751        _address: Address,
1752    ) -> ProviderResult<Option<reth_db_api::models::AccountBeforeTx>> {
1753        Err(ProviderError::UnsupportedProvider)
1754    }
1755
1756    fn account_changesets_range(
1757        &self,
1758        _range: impl std::ops::RangeBounds<BlockNumber>,
1759    ) -> ProviderResult<Vec<(BlockNumber, reth_db_api::models::AccountBeforeTx)>> {
1760        Err(ProviderError::UnsupportedProvider)
1761    }
1762}
1763
1764impl<P, Node, N> StateProviderFactory for RpcBlockchainStateProvider<P, Node, N>
1765where
1766    P: Provider<N> + Clone + 'static + Send + Sync,
1767    Node: NodeTypes + 'static,
1768    Node::ChainSpec: Send + Sync,
1769    N: Network,
1770    Self: Clone + 'static,
1771{
1772    fn latest(&self) -> Result<StateProviderBox, ProviderError> {
1773        Ok(Box::new(self.with_block_id(self.best_block_number()?.into())))
1774    }
1775
1776    fn state_by_block_id(&self, block_id: BlockId) -> Result<StateProviderBox, ProviderError> {
1777        Ok(Box::new(self.with_block_id(block_id)))
1778    }
1779
1780    fn state_by_block_number_or_tag(
1781        &self,
1782        number_or_tag: alloy_rpc_types::BlockNumberOrTag,
1783    ) -> Result<StateProviderBox, ProviderError> {
1784        match number_or_tag {
1785            alloy_rpc_types::BlockNumberOrTag::Latest => self.latest(),
1786            alloy_rpc_types::BlockNumberOrTag::Pending => self.pending(),
1787            alloy_rpc_types::BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1788            _ => Err(ProviderError::UnsupportedProvider),
1789        }
1790    }
1791
1792    fn history_by_block_number(
1793        &self,
1794        block_number: BlockNumber,
1795    ) -> Result<StateProviderBox, ProviderError> {
1796        Ok(Box::new(Self::new(
1797            self.provider.clone(),
1798            BlockId::number(block_number),
1799            self.node_types,
1800        )))
1801    }
1802
1803    fn history_by_block_hash(
1804        &self,
1805        block_hash: BlockHash,
1806    ) -> Result<StateProviderBox, ProviderError> {
1807        Ok(Box::new(self.with_block_id(BlockId::hash(block_hash))))
1808    }
1809
1810    fn state_by_block_hash(
1811        &self,
1812        block_hash: BlockHash,
1813    ) -> Result<StateProviderBox, ProviderError> {
1814        self.history_by_block_hash(block_hash)
1815    }
1816
1817    fn pending(&self) -> Result<StateProviderBox, ProviderError> {
1818        Ok(Box::new(self.clone()))
1819    }
1820
1821    fn pending_state_by_hash(
1822        &self,
1823        _block_hash: B256,
1824    ) -> Result<Option<StateProviderBox>, ProviderError> {
1825        // RPC provider doesn't support pending state by hash
1826        Err(ProviderError::UnsupportedProvider)
1827    }
1828
1829    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1830        Ok(None)
1831    }
1832}
1833
1834impl<P, Node, N> ChainSpecProvider for RpcBlockchainStateProvider<P, Node, N>
1835where
1836    P: Send + Sync + std::fmt::Debug,
1837    N: Network,
1838    Node: NodeTypes,
1839    Node::ChainSpec: Default,
1840{
1841    type ChainSpec = Node::ChainSpec;
1842
1843    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
1844        if let Some(chain_spec) = &self.chain_spec {
1845            chain_spec.clone()
1846        } else {
1847            // Fallback for when chain_spec is not provided
1848            Arc::new(Node::ChainSpec::default())
1849        }
1850    }
1851}
1852
1853// Note: FullExecutionDataProvider is already implemented via the blanket implementation
1854// for types that implement both ExecutionDataProvider and BlockExecutionForkProvider
1855
1856impl<P, Node, N> StatsReader for RpcBlockchainStateProvider<P, Node, N>
1857where
1858    P: Provider<N> + Clone + 'static,
1859    N: Network,
1860    Node: NodeTypes,
1861{
1862    fn count_entries<T: reth_db_api::table::Table>(&self) -> Result<usize, ProviderError> {
1863        Ok(0)
1864    }
1865}
1866
1867impl<P, Node, N> BlockBodyIndicesProvider for RpcBlockchainStateProvider<P, Node, N>
1868where
1869    P: Provider<N> + Clone + 'static,
1870    N: Network,
1871    Node: NodeTypes,
1872{
1873    fn block_body_indices(
1874        &self,
1875        _num: u64,
1876    ) -> Result<Option<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1877        Err(ProviderError::UnsupportedProvider)
1878    }
1879
1880    fn block_body_indices_range(
1881        &self,
1882        _range: RangeInclusive<u64>,
1883    ) -> Result<Vec<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1884        Err(ProviderError::UnsupportedProvider)
1885    }
1886}
1887
1888impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainStateProvider<P, Node, N>
1889where
1890    P: Send + Sync + std::fmt::Debug,
1891    N: Network,
1892    Node: NodeTypes,
1893{
1894    type Primitives = PrimitivesTy<Node>;
1895}
1896
1897impl<P, Node, N> ChainStateBlockReader for RpcBlockchainStateProvider<P, Node, N>
1898where
1899    P: Provider<N> + Clone + 'static,
1900    N: Network,
1901    Node: NodeTypes,
1902{
1903    fn last_finalized_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1904        Err(ProviderError::UnsupportedProvider)
1905    }
1906
1907    fn last_safe_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1908        Err(ProviderError::UnsupportedProvider)
1909    }
1910}
1911
1912impl<P, Node, N> ChainStateBlockWriter for RpcBlockchainStateProvider<P, Node, N>
1913where
1914    P: Provider<N> + Clone + 'static,
1915    N: Network,
1916    Node: NodeTypes,
1917{
1918    fn save_finalized_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1919        Err(ProviderError::UnsupportedProvider)
1920    }
1921
1922    fn save_safe_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1923        Err(ProviderError::UnsupportedProvider)
1924    }
1925}