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