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