reth_optimism_rpc/eth/
mod.rs

1//! OP-Reth `eth_` endpoint implementation.
2
3pub mod ext;
4pub mod receipt;
5pub mod transaction;
6
7mod block;
8mod call;
9mod pending_block;
10
11use alloy_primitives::U256;
12use op_alloy_network::Optimism;
13pub use receipt::{OpReceiptBuilder, OpReceiptFieldsBuilder};
14use reth_chain_state::CanonStateSubscriptions;
15use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
16use reth_evm::ConfigureEvm;
17use reth_network_api::NetworkInfo;
18use reth_node_api::{FullNodeComponents, NodePrimitives};
19use reth_node_builder::rpc::{EthApiBuilder, EthApiCtx};
20use reth_optimism_primitives::OpPrimitives;
21use reth_rpc::eth::{core::EthApiInner, DevSigner};
22use reth_rpc_eth_api::{
23    helpers::{
24        AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadBlock, LoadFee, LoadState,
25        SpawnBlocking, Trace,
26    },
27    EthApiTypes, FromEvmError, FullEthApiServer, RpcNodeCore, RpcNodeCoreExt,
28};
29use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasPriceOracle};
30use reth_storage_api::{
31    BlockNumReader, BlockReader, BlockReaderIdExt, ProviderBlock, ProviderHeader, ProviderReceipt,
32    ProviderTx, StageCheckpointReader, StateProviderFactory,
33};
34use reth_tasks::{
35    pool::{BlockingTaskGuard, BlockingTaskPool},
36    TaskSpawner,
37};
38use reth_transaction_pool::TransactionPool;
39use std::{fmt, sync::Arc};
40
41use crate::{OpEthApiError, SequencerClient};
42
43/// Adapter for [`EthApiInner`], which holds all the data required to serve core `eth_` API.
44pub type EthApiNodeBackend<N> = EthApiInner<
45    <N as RpcNodeCore>::Provider,
46    <N as RpcNodeCore>::Pool,
47    <N as RpcNodeCore>::Network,
48    <N as RpcNodeCore>::Evm,
49>;
50
51/// A helper trait with requirements for [`RpcNodeCore`] to be used in [`OpEthApi`].
52pub trait OpNodeCore: RpcNodeCore<Provider: BlockReader> {}
53impl<T> OpNodeCore for T where T: RpcNodeCore<Provider: BlockReader> {}
54
55/// OP-Reth `Eth` API implementation.
56///
57/// This type provides the functionality for handling `eth_` related requests.
58///
59/// This wraps a default `Eth` implementation, and provides additional functionality where the
60/// optimism spec deviates from the default (ethereum) spec, e.g. transaction forwarding to the
61/// sequencer, receipts, additional RPC fields for transaction receipts.
62///
63/// This type implements the [`FullEthApi`](reth_rpc_eth_api::helpers::FullEthApi) by implemented
64/// all the `Eth` helper traits and prerequisite traits.
65#[derive(Clone)]
66pub struct OpEthApi<N: OpNodeCore> {
67    /// Gateway to node's core components.
68    inner: Arc<OpEthApiInner<N>>,
69}
70
71impl<N> OpEthApi<N>
72where
73    N: OpNodeCore<
74        Provider: BlockReaderIdExt
75                      + ChainSpecProvider
76                      + CanonStateSubscriptions<Primitives = OpPrimitives>
77                      + Clone
78                      + 'static,
79    >,
80{
81    /// Returns a reference to the [`EthApiNodeBackend`].
82    pub fn eth_api(&self) -> &EthApiNodeBackend<N> {
83        self.inner.eth_api()
84    }
85
86    /// Returns the configured sequencer client, if any.
87    pub fn sequencer_client(&self) -> Option<&SequencerClient> {
88        self.inner.sequencer_client()
89    }
90
91    /// Build a [`OpEthApi`] using [`OpEthApiBuilder`].
92    pub const fn builder() -> OpEthApiBuilder {
93        OpEthApiBuilder::new()
94    }
95}
96
97impl<N> EthApiTypes for OpEthApi<N>
98where
99    Self: Send + Sync,
100    N: OpNodeCore,
101{
102    type Error = OpEthApiError;
103    type NetworkTypes = Optimism;
104    type TransactionCompat = Self;
105
106    fn tx_resp_builder(&self) -> &Self::TransactionCompat {
107        self
108    }
109}
110
111impl<N> RpcNodeCore for OpEthApi<N>
112where
113    N: OpNodeCore,
114{
115    type Primitives = OpPrimitives;
116    type Provider = N::Provider;
117    type Pool = N::Pool;
118    type Evm = <N as RpcNodeCore>::Evm;
119    type Network = <N as RpcNodeCore>::Network;
120    type PayloadBuilder = ();
121
122    #[inline]
123    fn pool(&self) -> &Self::Pool {
124        self.inner.eth_api.pool()
125    }
126
127    #[inline]
128    fn evm_config(&self) -> &Self::Evm {
129        self.inner.eth_api.evm_config()
130    }
131
132    #[inline]
133    fn network(&self) -> &Self::Network {
134        self.inner.eth_api.network()
135    }
136
137    #[inline]
138    fn payload_builder(&self) -> &Self::PayloadBuilder {
139        &()
140    }
141
142    #[inline]
143    fn provider(&self) -> &Self::Provider {
144        self.inner.eth_api.provider()
145    }
146}
147
148impl<N> RpcNodeCoreExt for OpEthApi<N>
149where
150    N: OpNodeCore,
151{
152    #[inline]
153    fn cache(&self) -> &EthStateCache<ProviderBlock<N::Provider>, ProviderReceipt<N::Provider>> {
154        self.inner.eth_api.cache()
155    }
156}
157
158impl<N> EthApiSpec for OpEthApi<N>
159where
160    N: OpNodeCore<
161        Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>
162                      + BlockNumReader
163                      + StageCheckpointReader,
164        Network: NetworkInfo,
165    >,
166{
167    type Transaction = ProviderTx<Self::Provider>;
168
169    #[inline]
170    fn starting_block(&self) -> U256 {
171        self.inner.eth_api.starting_block()
172    }
173
174    #[inline]
175    fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner<ProviderTx<Self::Provider>>>>> {
176        self.inner.eth_api.signers()
177    }
178}
179
180impl<N> SpawnBlocking for OpEthApi<N>
181where
182    Self: Send + Sync + Clone + 'static,
183    N: OpNodeCore,
184{
185    #[inline]
186    fn io_task_spawner(&self) -> impl TaskSpawner {
187        self.inner.eth_api.task_spawner()
188    }
189
190    #[inline]
191    fn tracing_task_pool(&self) -> &BlockingTaskPool {
192        self.inner.eth_api.blocking_task_pool()
193    }
194
195    #[inline]
196    fn tracing_task_guard(&self) -> &BlockingTaskGuard {
197        self.inner.eth_api.blocking_task_guard()
198    }
199}
200
201impl<N> LoadFee for OpEthApi<N>
202where
203    Self: LoadBlock<Provider = N::Provider>,
204    N: OpNodeCore<
205        Provider: BlockReaderIdExt
206                      + ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
207                      + StateProviderFactory,
208    >,
209{
210    #[inline]
211    fn gas_oracle(&self) -> &GasPriceOracle<Self::Provider> {
212        self.inner.eth_api.gas_oracle()
213    }
214
215    #[inline]
216    fn fee_history_cache(&self) -> &FeeHistoryCache {
217        self.inner.eth_api.fee_history_cache()
218    }
219}
220
221impl<N> LoadState for OpEthApi<N> where
222    N: OpNodeCore<
223        Provider: StateProviderFactory + ChainSpecProvider<ChainSpec: EthereumHardforks>,
224        Pool: TransactionPool,
225    >
226{
227}
228
229impl<N> EthState for OpEthApi<N>
230where
231    Self: LoadState + SpawnBlocking,
232    N: OpNodeCore,
233{
234    #[inline]
235    fn max_proof_window(&self) -> u64 {
236        self.inner.eth_api.eth_proof_window()
237    }
238}
239
240impl<N> EthFees for OpEthApi<N>
241where
242    Self: LoadFee,
243    N: OpNodeCore,
244{
245}
246
247impl<N> Trace for OpEthApi<N>
248where
249    Self: RpcNodeCore<Provider: BlockReader>
250        + LoadState<
251            Evm: ConfigureEvm<
252                Primitives: NodePrimitives<
253                    BlockHeader = ProviderHeader<Self::Provider>,
254                    SignedTx = ProviderTx<Self::Provider>,
255                >,
256            >,
257            Error: FromEvmError<Self::Evm>,
258        >,
259    N: OpNodeCore,
260{
261}
262
263impl<N> AddDevSigners for OpEthApi<N>
264where
265    N: OpNodeCore,
266{
267    fn with_dev_accounts(&self) {
268        *self.inner.eth_api.signers().write() = DevSigner::random_signers(20)
269    }
270}
271
272impl<N: OpNodeCore> fmt::Debug for OpEthApi<N> {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        f.debug_struct("OpEthApi").finish_non_exhaustive()
275    }
276}
277
278/// Container type `OpEthApi`
279struct OpEthApiInner<N: OpNodeCore> {
280    /// Gateway to node's core components.
281    eth_api: EthApiNodeBackend<N>,
282    /// Sequencer client, configured to forward submitted transactions to sequencer of given OP
283    /// network.
284    sequencer_client: Option<SequencerClient>,
285}
286
287impl<N: OpNodeCore> OpEthApiInner<N> {
288    /// Returns a reference to the [`EthApiNodeBackend`].
289    const fn eth_api(&self) -> &EthApiNodeBackend<N> {
290        &self.eth_api
291    }
292
293    /// Returns the configured sequencer client, if any.
294    const fn sequencer_client(&self) -> Option<&SequencerClient> {
295        self.sequencer_client.as_ref()
296    }
297}
298
299/// Builds [`OpEthApi`] for Optimism.
300#[derive(Debug, Default)]
301pub struct OpEthApiBuilder {
302    /// Sequencer client, configured to forward submitted transactions to sequencer of given OP
303    /// network.
304    sequencer_client: Option<SequencerClient>,
305}
306
307impl OpEthApiBuilder {
308    /// Creates a [`OpEthApiBuilder`] instance from core components.
309    pub const fn new() -> Self {
310        Self { sequencer_client: None }
311    }
312
313    /// With a [`SequencerClient`].
314    pub fn with_sequencer(mut self, sequencer_client: Option<SequencerClient>) -> Self {
315        self.sequencer_client = sequencer_client;
316        self
317    }
318}
319
320impl<N> EthApiBuilder<N> for OpEthApiBuilder
321where
322    N: FullNodeComponents,
323    OpEthApi<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
324{
325    type EthApi = OpEthApi<N>;
326
327    async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
328        let Self { sequencer_client } = self;
329        let eth_api = reth_rpc::EthApiBuilder::new(
330            ctx.components.provider().clone(),
331            ctx.components.pool().clone(),
332            ctx.components.network().clone(),
333            ctx.components.evm_config().clone(),
334        )
335        .eth_cache(ctx.cache)
336        .task_spawner(ctx.components.task_executor().clone())
337        .gas_cap(ctx.config.rpc_gas_cap.into())
338        .max_simulate_blocks(ctx.config.rpc_max_simulate_blocks)
339        .eth_proof_window(ctx.config.eth_proof_window)
340        .fee_history_cache_config(ctx.config.fee_history_cache)
341        .proof_permits(ctx.config.proof_permits)
342        .gas_oracle_config(ctx.config.gas_oracle)
343        .build_inner();
344
345        Ok(OpEthApi { inner: Arc::new(OpEthApiInner { eth_api, sequencer_client }) })
346    }
347}