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