1pub 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
43pub 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
51pub trait OpNodeCore: RpcNodeCore<Provider: BlockReader> {}
53impl<T> OpNodeCore for T where T: RpcNodeCore<Provider: BlockReader> {}
54
55#[derive(Clone)]
66pub struct OpEthApi<N: OpNodeCore> {
67 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 pub fn eth_api(&self) -> &EthApiNodeBackend<N> {
83 self.inner.eth_api()
84 }
85
86 pub fn sequencer_client(&self) -> Option<&SequencerClient> {
88 self.inner.sequencer_client()
89 }
90
91 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
278struct OpEthApiInner<N: OpNodeCore> {
280 eth_api: EthApiNodeBackend<N>,
282 sequencer_client: Option<SequencerClient>,
285}
286
287impl<N: OpNodeCore> OpEthApiInner<N> {
288 const fn eth_api(&self) -> &EthApiNodeBackend<N> {
290 &self.eth_api
291 }
292
293 const fn sequencer_client(&self) -> Option<&SequencerClient> {
295 self.sequencer_client.as_ref()
296 }
297}
298
299#[derive(Debug, Default)]
301pub struct OpEthApiBuilder {
302 sequencer_client: Option<SequencerClient>,
305}
306
307impl OpEthApiBuilder {
308 pub const fn new() -> Self {
310 Self { sequencer_client: None }
311 }
312
313 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}