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 transaction_block(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
679        Err(ProviderError::UnsupportedProvider)
680    }
681
682    fn transactions_by_block(
683        &self,
684        block: BlockHashOrNumber,
685    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
686        let block_response = self.block_on_async(async {
687            self.provider.get_block(block.into()).full().await.map_err(ProviderError::other)
688        })?;
689
690        let Some(block_response) = block_response else {
691            // If the block was not found, return None
692            return Ok(None);
693        };
694
695        // Convert the network block response to primitive block
696        let block = <BlockTy<Node> as TryFromBlockResponse<N>>::from_block_response(block_response)
697            .map_err(ProviderError::other)?;
698
699        Ok(Some(block.into_body().into_transactions()))
700    }
701
702    fn transactions_by_block_range(
703        &self,
704        _range: impl RangeBounds<BlockNumber>,
705    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
706        Err(ProviderError::UnsupportedProvider)
707    }
708
709    fn transactions_by_tx_range(
710        &self,
711        _range: impl RangeBounds<TxNumber>,
712    ) -> ProviderResult<Vec<Self::Transaction>> {
713        Err(ProviderError::UnsupportedProvider)
714    }
715
716    fn senders_by_tx_range(
717        &self,
718        _range: impl RangeBounds<TxNumber>,
719    ) -> ProviderResult<Vec<Address>> {
720        Err(ProviderError::UnsupportedProvider)
721    }
722
723    fn transaction_sender(&self, _id: TxNumber) -> ProviderResult<Option<Address>> {
724        Err(ProviderError::UnsupportedProvider)
725    }
726}
727
728impl<P, Node, N> StateProviderFactory for RpcBlockchainProvider<P, Node, N>
729where
730    P: Provider<N> + Clone + 'static,
731    N: Network,
732    Node: NodeTypes,
733{
734    fn latest(&self) -> Result<StateProviderBox, ProviderError> {
735        Ok(Box::new(self.create_state_provider(self.best_block_number()?.into())))
736    }
737
738    fn state_by_block_id(&self, block_id: BlockId) -> Result<StateProviderBox, ProviderError> {
739        Ok(Box::new(self.create_state_provider(block_id)))
740    }
741
742    fn state_by_block_number_or_tag(
743        &self,
744        number_or_tag: alloy_rpc_types::BlockNumberOrTag,
745    ) -> Result<StateProviderBox, ProviderError> {
746        match number_or_tag {
747            alloy_rpc_types::BlockNumberOrTag::Latest => self.latest(),
748            alloy_rpc_types::BlockNumberOrTag::Pending => self.pending(),
749            alloy_rpc_types::BlockNumberOrTag::Number(num) => self.state_by_block_number(num),
750            _ => Err(ProviderError::UnsupportedProvider),
751        }
752    }
753
754    fn history_by_block_number(
755        &self,
756        block_number: BlockNumber,
757    ) -> Result<StateProviderBox, ProviderError> {
758        self.state_by_block_number(block_number)
759    }
760
761    fn history_by_block_hash(
762        &self,
763        block_hash: BlockHash,
764    ) -> Result<StateProviderBox, ProviderError> {
765        self.state_by_block_hash(block_hash)
766    }
767
768    fn state_by_block_hash(
769        &self,
770        block_hash: BlockHash,
771    ) -> Result<StateProviderBox, ProviderError> {
772        trace!(target: "alloy-provider", ?block_hash, "Getting state provider by block hash");
773
774        let block = self.block_on_async(async {
775            self.provider
776                .get_block_by_hash(block_hash)
777                .await
778                .map_err(ProviderError::other)?
779                .ok_or(ProviderError::BlockHashNotFound(block_hash))
780        })?;
781
782        let block_number = block.header().number();
783        Ok(Box::new(self.create_state_provider(BlockId::number(block_number))))
784    }
785
786    fn pending(&self) -> Result<StateProviderBox, ProviderError> {
787        trace!(target: "alloy-provider", "Getting pending state provider");
788        self.latest()
789    }
790
791    fn pending_state_by_hash(
792        &self,
793        _block_hash: B256,
794    ) -> Result<Option<StateProviderBox>, ProviderError> {
795        // RPC provider doesn't support pending state by hash
796        Err(ProviderError::UnsupportedProvider)
797    }
798
799    fn maybe_pending(&self) -> Result<Option<StateProviderBox>, ProviderError> {
800        Ok(None)
801    }
802}
803
804impl<P, Node, N> DatabaseProviderFactory for RpcBlockchainProvider<P, Node, N>
805where
806    P: Provider<N> + Clone + 'static,
807    N: Network,
808    Node: NodeTypes,
809{
810    type DB = DatabaseMock;
811    type Provider = RpcBlockchainStateProvider<P, Node, N>;
812    type ProviderRW = RpcBlockchainStateProvider<P, Node, N>;
813
814    fn database_provider_ro(&self) -> Result<Self::Provider, ProviderError> {
815        // RPC provider returns a new state provider
816        let block_number = self.block_on_async(async {
817            self.provider.get_block_number().await.map_err(ProviderError::other)
818        })?;
819
820        Ok(self.create_state_provider(BlockId::number(block_number)))
821    }
822
823    fn database_provider_rw(&self) -> Result<Self::ProviderRW, ProviderError> {
824        // RPC provider returns a new state provider
825        let block_number = self.block_on_async(async {
826            self.provider.get_block_number().await.map_err(ProviderError::other)
827        })?;
828
829        Ok(self.create_state_provider(BlockId::number(block_number)))
830    }
831}
832
833impl<P, Node, N> CanonChainTracker for RpcBlockchainProvider<P, Node, N>
834where
835    P: Provider<N> + Clone + 'static,
836    N: Network,
837    Node: NodeTypes,
838{
839    type Header = alloy_consensus::Header;
840    fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
841        // No-op for RPC provider
842    }
843
844    fn last_received_update_timestamp(&self) -> Option<std::time::Instant> {
845        None
846    }
847
848    fn set_canonical_head(&self, _header: SealedHeader<Self::Header>) {
849        // No-op for RPC provider
850    }
851
852    fn set_safe(&self, _header: SealedHeader<Self::Header>) {
853        // No-op for RPC provider
854    }
855
856    fn set_finalized(&self, _header: SealedHeader<Self::Header>) {
857        // No-op for RPC provider
858    }
859}
860
861impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainProvider<P, Node, N>
862where
863    P: Send + Sync,
864    N: Send + Sync,
865    Node: NodeTypes,
866{
867    type Primitives = PrimitivesTy<Node>;
868}
869
870impl<P, Node, N> CanonStateSubscriptions for RpcBlockchainProvider<P, Node, N>
871where
872    P: Provider<N> + Clone + 'static,
873    N: Network,
874    Node: NodeTypes,
875{
876    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<PrimitivesTy<Node>> {
877        trace!(target: "alloy-provider", "Subscribing to canonical state notifications");
878        self.canon_state_notification.subscribe()
879    }
880}
881
882impl<P, Node, N> ChainSpecProvider for RpcBlockchainProvider<P, Node, N>
883where
884    P: Send + Sync,
885    N: Send + Sync,
886    Node: NodeTypes,
887    Node::ChainSpec: Default,
888{
889    type ChainSpec = Node::ChainSpec;
890
891    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
892        self.chain_spec.clone()
893    }
894}
895
896/// RPC-based state provider implementation that fetches blockchain state via remote RPC calls.
897///
898/// This is the state provider counterpart to `RpcBlockchainProvider`, handling state queries
899/// at specific block heights via RPC instead of local database access.
900pub struct RpcBlockchainStateProvider<P, Node, N = alloy_network::AnyNetwork>
901where
902    Node: NodeTypes,
903{
904    /// The underlying Alloy provider
905    provider: P,
906    /// The block ID to fetch state at
907    block_id: BlockId,
908    /// Node types marker
909    node_types: std::marker::PhantomData<Node>,
910    /// Network marker
911    network: std::marker::PhantomData<N>,
912    /// Cached chain spec (shared with parent provider)
913    chain_spec: Option<Arc<Node::ChainSpec>>,
914    /// Whether to enable state root calculation
915    compute_state_root: bool,
916    /// Cached bytecode for accounts
917    ///
918    /// Since the state provider is short-lived, we don't worry about memory leaks.
919    code_store: RwLock<HashMap<B256, Bytecode>>,
920    /// Whether to use Reth-specific RPC methods for better performance
921    reth_rpc_support: bool,
922}
923
924impl<P: std::fmt::Debug, Node: NodeTypes, N> std::fmt::Debug
925    for RpcBlockchainStateProvider<P, Node, N>
926{
927    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
928        f.debug_struct("RpcBlockchainStateProvider")
929            .field("provider", &self.provider)
930            .field("block_id", &self.block_id)
931            .finish()
932    }
933}
934
935impl<P: Clone, Node: NodeTypes, N> RpcBlockchainStateProvider<P, Node, N> {
936    /// Creates a new state provider for the given block
937    pub fn new(
938        provider: P,
939        block_id: BlockId,
940        _primitives: std::marker::PhantomData<Node>,
941    ) -> Self {
942        Self {
943            provider,
944            block_id,
945            node_types: std::marker::PhantomData,
946            network: std::marker::PhantomData,
947            chain_spec: None,
948            compute_state_root: false,
949            code_store: RwLock::new(HashMap::default()),
950            reth_rpc_support: true,
951        }
952    }
953
954    /// Creates a new state provider with a cached chain spec
955    pub fn with_chain_spec(
956        provider: P,
957        block_id: BlockId,
958        chain_spec: Arc<Node::ChainSpec>,
959    ) -> Self {
960        Self {
961            provider,
962            block_id,
963            node_types: std::marker::PhantomData,
964            network: std::marker::PhantomData,
965            chain_spec: Some(chain_spec),
966            compute_state_root: false,
967            code_store: RwLock::new(HashMap::default()),
968            reth_rpc_support: true,
969        }
970    }
971
972    /// Helper function to execute async operations in a blocking context
973    fn block_on_async<F, T>(&self, fut: F) -> T
974    where
975        F: Future<Output = T>,
976    {
977        tokio::task::block_in_place(move || Handle::current().block_on(fut))
978    }
979
980    /// Helper function to create a new state provider with a different block ID
981    fn with_block_id(&self, block_id: BlockId) -> Self {
982        Self {
983            provider: self.provider.clone(),
984            block_id,
985            node_types: self.node_types,
986            network: self.network,
987            chain_spec: self.chain_spec.clone(),
988            compute_state_root: self.compute_state_root,
989            code_store: RwLock::new(HashMap::default()),
990            reth_rpc_support: self.reth_rpc_support,
991        }
992    }
993
994    /// Helper function to enable state root calculation
995    ///
996    /// If enabled, the node will compute the state root and updates.
997    /// When disabled, it will return zero for state root and no updates.
998    pub const fn with_compute_state_root(mut self, is_enable: bool) -> Self {
999        self.compute_state_root = is_enable;
1000        self
1001    }
1002
1003    /// Sets whether to use Reth-specific RPC methods for better performance
1004    ///
1005    /// If enabled, the node will use Reth's RPC methods (`debug_codeByHash` and
1006    /// `eth_getAccountInfo`) to speed up account information retrieval. When disabled, it will
1007    /// use multiple standard RPC calls to get account information.
1008    pub const fn with_reth_rpc_support(mut self, is_enable: bool) -> Self {
1009        self.reth_rpc_support = is_enable;
1010        self
1011    }
1012
1013    /// Get account information from RPC
1014    fn get_account(&self, address: Address) -> Result<Option<Account>, ProviderError>
1015    where
1016        P: Provider<N> + Clone + 'static,
1017        N: Network,
1018    {
1019        let account_info = self.block_on_async(async {
1020            // Get account info in a single RPC call using `eth_getAccountInfo`
1021            if self.reth_rpc_support {
1022                return self
1023                    .provider
1024                    .get_account_info(address)
1025                    .block_id(self.block_id)
1026                    .await
1027                    .map_err(ProviderError::other);
1028            }
1029            // Get account info in multiple RPC calls
1030            let nonce = self.provider.get_transaction_count(address).block_id(self.block_id);
1031            let balance = self.provider.get_balance(address).block_id(self.block_id);
1032            let code = self.provider.get_code_at(address).block_id(self.block_id);
1033
1034            let (nonce, balance, code) = tokio::join!(nonce, balance, code,);
1035
1036            let account_info = AccountInfo {
1037                balance: balance.map_err(ProviderError::other)?,
1038                nonce: nonce.map_err(ProviderError::other)?,
1039                code: code.map_err(ProviderError::other)?,
1040            };
1041
1042            let code_hash = account_info.code_hash();
1043            if code_hash != KECCAK_EMPTY {
1044                // Insert code into the cache
1045                self.code_store
1046                    .write()
1047                    .insert(code_hash, Bytecode::new_raw(account_info.code.clone()));
1048            }
1049
1050            Ok(account_info)
1051        })?;
1052
1053        // Only return account if it exists (has balance, nonce, or code)
1054        if account_info.balance.is_zero() && account_info.nonce == 0 && account_info.code.is_empty()
1055        {
1056            Ok(None)
1057        } else {
1058            let bytecode_hash =
1059                if account_info.code.is_empty() { None } else { Some(account_info.code_hash()) };
1060
1061            Ok(Some(Account {
1062                balance: account_info.balance,
1063                nonce: account_info.nonce,
1064                bytecode_hash,
1065            }))
1066        }
1067    }
1068}
1069
1070impl<P, Node, N> StateProvider for RpcBlockchainStateProvider<P, Node, N>
1071where
1072    P: Provider<N> + Clone + 'static,
1073    N: Network,
1074    Node: NodeTypes,
1075{
1076    fn storage(
1077        &self,
1078        address: Address,
1079        storage_key: StorageKey,
1080    ) -> Result<Option<U256>, ProviderError> {
1081        self.block_on_async(async {
1082            Ok(Some(
1083                self.provider
1084                    .get_storage_at(address, storage_key.into())
1085                    .block_id(self.block_id)
1086                    .await
1087                    .map_err(ProviderError::other)?,
1088            ))
1089        })
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.read().get(code_hash).cloned());
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<bool> {
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 transaction_block(&self, _id: TxNumber) -> Result<Option<BlockNumber>, ProviderError> {
1575        Err(ProviderError::UnsupportedProvider)
1576    }
1577
1578    fn transactions_by_block(
1579        &self,
1580        _block: alloy_rpc_types::BlockHashOrNumber,
1581    ) -> Result<Option<Vec<Self::Transaction>>, ProviderError> {
1582        Err(ProviderError::UnsupportedProvider)
1583    }
1584
1585    fn transactions_by_block_range(
1586        &self,
1587        _range: impl RangeBounds<BlockNumber>,
1588    ) -> Result<Vec<Vec<Self::Transaction>>, ProviderError> {
1589        Err(ProviderError::UnsupportedProvider)
1590    }
1591
1592    fn transactions_by_tx_range(
1593        &self,
1594        _range: impl RangeBounds<TxNumber>,
1595    ) -> Result<Vec<Self::Transaction>, ProviderError> {
1596        Err(ProviderError::UnsupportedProvider)
1597    }
1598
1599    fn senders_by_tx_range(
1600        &self,
1601        _range: impl RangeBounds<TxNumber>,
1602    ) -> Result<Vec<Address>, ProviderError> {
1603        Err(ProviderError::UnsupportedProvider)
1604    }
1605
1606    fn transaction_sender(&self, _id: TxNumber) -> Result<Option<Address>, ProviderError> {
1607        Err(ProviderError::UnsupportedProvider)
1608    }
1609}
1610
1611impl<P, Node, N> ReceiptProvider for RpcBlockchainStateProvider<P, Node, N>
1612where
1613    P: Provider<N> + Clone + 'static,
1614    N: Network,
1615    Node: NodeTypes,
1616{
1617    type Receipt = ReceiptTy<Node>;
1618
1619    fn receipt(&self, _id: TxNumber) -> Result<Option<Self::Receipt>, ProviderError> {
1620        Err(ProviderError::UnsupportedProvider)
1621    }
1622
1623    fn receipt_by_hash(&self, _hash: B256) -> Result<Option<Self::Receipt>, ProviderError> {
1624        Err(ProviderError::UnsupportedProvider)
1625    }
1626
1627    fn receipts_by_block(
1628        &self,
1629        _block: alloy_rpc_types::BlockHashOrNumber,
1630    ) -> Result<Option<Vec<Self::Receipt>>, ProviderError> {
1631        Err(ProviderError::UnsupportedProvider)
1632    }
1633
1634    fn receipts_by_tx_range(
1635        &self,
1636        _range: impl RangeBounds<TxNumber>,
1637    ) -> Result<Vec<Self::Receipt>, ProviderError> {
1638        Err(ProviderError::UnsupportedProvider)
1639    }
1640
1641    fn receipts_by_block_range(
1642        &self,
1643        _range: RangeInclusive<BlockNumber>,
1644    ) -> Result<Vec<Vec<Self::Receipt>>, ProviderError> {
1645        Err(ProviderError::UnsupportedProvider)
1646    }
1647}
1648
1649impl<P, Node, N> HeaderProvider for RpcBlockchainStateProvider<P, Node, N>
1650where
1651    P: Provider<N> + Clone + 'static,
1652    N: Network,
1653    Node: NodeTypes,
1654{
1655    type Header = HeaderTy<Node>;
1656
1657    fn header(&self, _block_hash: BlockHash) -> Result<Option<Self::Header>, ProviderError> {
1658        Err(ProviderError::UnsupportedProvider)
1659    }
1660
1661    fn header_by_number(&self, _num: BlockNumber) -> Result<Option<Self::Header>, ProviderError> {
1662        Err(ProviderError::UnsupportedProvider)
1663    }
1664
1665    fn headers_range(
1666        &self,
1667        _range: impl RangeBounds<BlockNumber>,
1668    ) -> Result<Vec<Self::Header>, ProviderError> {
1669        Err(ProviderError::UnsupportedProvider)
1670    }
1671
1672    fn sealed_header(
1673        &self,
1674        _number: BlockNumber,
1675    ) -> Result<Option<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1676        Err(ProviderError::UnsupportedProvider)
1677    }
1678
1679    fn sealed_headers_range(
1680        &self,
1681        _range: impl RangeBounds<BlockNumber>,
1682    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1683        Err(ProviderError::UnsupportedProvider)
1684    }
1685
1686    fn sealed_headers_while(
1687        &self,
1688        _range: impl RangeBounds<BlockNumber>,
1689        _predicate: impl FnMut(&SealedHeader<HeaderTy<Node>>) -> bool,
1690    ) -> Result<Vec<SealedHeader<HeaderTy<Node>>>, ProviderError> {
1691        Err(ProviderError::UnsupportedProvider)
1692    }
1693}
1694
1695impl<P, Node, N> PruneCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1696where
1697    P: Provider<N> + Clone + 'static,
1698    N: Network,
1699    Node: NodeTypes,
1700{
1701    fn get_prune_checkpoint(
1702        &self,
1703        _segment: PruneSegment,
1704    ) -> Result<Option<PruneCheckpoint>, ProviderError> {
1705        Err(ProviderError::UnsupportedProvider)
1706    }
1707
1708    fn get_prune_checkpoints(&self) -> Result<Vec<(PruneSegment, PruneCheckpoint)>, ProviderError> {
1709        Err(ProviderError::UnsupportedProvider)
1710    }
1711}
1712
1713impl<P, Node, N> StageCheckpointReader for RpcBlockchainStateProvider<P, Node, N>
1714where
1715    P: Provider<N> + Clone + 'static,
1716    N: Network,
1717    Node: NodeTypes,
1718{
1719    fn get_stage_checkpoint(&self, _id: StageId) -> Result<Option<StageCheckpoint>, ProviderError> {
1720        Err(ProviderError::UnsupportedProvider)
1721    }
1722
1723    fn get_stage_checkpoint_progress(
1724        &self,
1725        _id: StageId,
1726    ) -> Result<Option<Vec<u8>>, ProviderError> {
1727        Err(ProviderError::UnsupportedProvider)
1728    }
1729
1730    fn get_all_checkpoints(&self) -> Result<Vec<(String, StageCheckpoint)>, ProviderError> {
1731        Err(ProviderError::UnsupportedProvider)
1732    }
1733}
1734
1735impl<P, Node, N> ChangeSetReader for RpcBlockchainStateProvider<P, Node, N>
1736where
1737    P: Provider<N> + Clone + 'static,
1738    N: Network,
1739    Node: NodeTypes,
1740{
1741    fn account_block_changeset(
1742        &self,
1743        _block_number: BlockNumber,
1744    ) -> Result<Vec<reth_db_api::models::AccountBeforeTx>, ProviderError> {
1745        Err(ProviderError::UnsupportedProvider)
1746    }
1747
1748    fn get_account_before_block(
1749        &self,
1750        _block_number: BlockNumber,
1751        _address: Address,
1752    ) -> ProviderResult<Option<reth_db_api::models::AccountBeforeTx>> {
1753        Err(ProviderError::UnsupportedProvider)
1754    }
1755}
1756
1757impl<P, Node, N> StateProviderFactory for RpcBlockchainStateProvider<P, Node, N>
1758where
1759    P: Provider<N> + Clone + 'static + Send + Sync,
1760    Node: NodeTypes + 'static,
1761    Node::ChainSpec: Send + Sync,
1762    N: Network,
1763    Self: Clone + 'static,
1764{
1765    fn latest(&self) -> Result<StateProviderBox, ProviderError> {
1766        Ok(Box::new(self.with_block_id(self.best_block_number()?.into())))
1767    }
1768
1769    fn state_by_block_id(&self, block_id: BlockId) -> Result<StateProviderBox, ProviderError> {
1770        Ok(Box::new(self.with_block_id(block_id)))
1771    }
1772
1773    fn state_by_block_number_or_tag(
1774        &self,
1775        number_or_tag: alloy_rpc_types::BlockNumberOrTag,
1776    ) -> Result<StateProviderBox, ProviderError> {
1777        match number_or_tag {
1778            alloy_rpc_types::BlockNumberOrTag::Latest => self.latest(),
1779            alloy_rpc_types::BlockNumberOrTag::Pending => self.pending(),
1780            alloy_rpc_types::BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1781            _ => Err(ProviderError::UnsupportedProvider),
1782        }
1783    }
1784
1785    fn history_by_block_number(
1786        &self,
1787        block_number: BlockNumber,
1788    ) -> Result<StateProviderBox, ProviderError> {
1789        Ok(Box::new(Self::new(
1790            self.provider.clone(),
1791            BlockId::number(block_number),
1792            self.node_types,
1793        )))
1794    }
1795
1796    fn history_by_block_hash(
1797        &self,
1798        block_hash: BlockHash,
1799    ) -> Result<StateProviderBox, ProviderError> {
1800        Ok(Box::new(self.with_block_id(BlockId::hash(block_hash))))
1801    }
1802
1803    fn state_by_block_hash(
1804        &self,
1805        block_hash: BlockHash,
1806    ) -> Result<StateProviderBox, ProviderError> {
1807        self.history_by_block_hash(block_hash)
1808    }
1809
1810    fn pending(&self) -> Result<StateProviderBox, ProviderError> {
1811        Ok(Box::new(self.clone()))
1812    }
1813
1814    fn pending_state_by_hash(
1815        &self,
1816        _block_hash: B256,
1817    ) -> Result<Option<StateProviderBox>, ProviderError> {
1818        // RPC provider doesn't support pending state by hash
1819        Err(ProviderError::UnsupportedProvider)
1820    }
1821
1822    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1823        Ok(None)
1824    }
1825}
1826
1827impl<P, Node, N> ChainSpecProvider for RpcBlockchainStateProvider<P, Node, N>
1828where
1829    P: Send + Sync + std::fmt::Debug,
1830    N: Send + Sync,
1831    Node: NodeTypes,
1832    Node::ChainSpec: Default,
1833{
1834    type ChainSpec = Node::ChainSpec;
1835
1836    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
1837        if let Some(chain_spec) = &self.chain_spec {
1838            chain_spec.clone()
1839        } else {
1840            // Fallback for when chain_spec is not provided
1841            Arc::new(Node::ChainSpec::default())
1842        }
1843    }
1844}
1845
1846// Note: FullExecutionDataProvider is already implemented via the blanket implementation
1847// for types that implement both ExecutionDataProvider and BlockExecutionForkProvider
1848
1849impl<P, Node, N> StatsReader for RpcBlockchainStateProvider<P, Node, N>
1850where
1851    P: Provider<N> + Clone + 'static,
1852    N: Network,
1853    Node: NodeTypes,
1854{
1855    fn count_entries<T: reth_db_api::table::Table>(&self) -> Result<usize, ProviderError> {
1856        Ok(0)
1857    }
1858}
1859
1860impl<P, Node, N> BlockBodyIndicesProvider for RpcBlockchainStateProvider<P, Node, N>
1861where
1862    P: Provider<N> + Clone + 'static,
1863    N: Network,
1864    Node: NodeTypes,
1865{
1866    fn block_body_indices(
1867        &self,
1868        _num: u64,
1869    ) -> Result<Option<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1870        Err(ProviderError::UnsupportedProvider)
1871    }
1872
1873    fn block_body_indices_range(
1874        &self,
1875        _range: RangeInclusive<u64>,
1876    ) -> Result<Vec<reth_db_api::models::StoredBlockBodyIndices>, ProviderError> {
1877        Err(ProviderError::UnsupportedProvider)
1878    }
1879}
1880
1881impl<P, Node, N> NodePrimitivesProvider for RpcBlockchainStateProvider<P, Node, N>
1882where
1883    P: Send + Sync + std::fmt::Debug,
1884    N: Send + Sync,
1885    Node: NodeTypes,
1886{
1887    type Primitives = PrimitivesTy<Node>;
1888}
1889
1890impl<P, Node, N> ChainStateBlockReader for RpcBlockchainStateProvider<P, Node, N>
1891where
1892    P: Provider<N> + Clone + 'static,
1893    N: Network,
1894    Node: NodeTypes,
1895{
1896    fn last_finalized_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1897        Err(ProviderError::UnsupportedProvider)
1898    }
1899
1900    fn last_safe_block_number(&self) -> Result<Option<BlockNumber>, ProviderError> {
1901        Err(ProviderError::UnsupportedProvider)
1902    }
1903}
1904
1905impl<P, Node, N> ChainStateBlockWriter for RpcBlockchainStateProvider<P, Node, N>
1906where
1907    P: Provider<N> + Clone + 'static,
1908    N: Network,
1909    Node: NodeTypes,
1910{
1911    fn save_finalized_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1912        Err(ProviderError::UnsupportedProvider)
1913    }
1914
1915    fn save_safe_block_number(&self, _block_number: BlockNumber) -> Result<(), ProviderError> {
1916        Err(ProviderError::UnsupportedProvider)
1917    }
1918}