reth_rpc/eth/
builder.rs

1//! `EthApiBuilder` implementation
2
3use crate::{eth::core::EthApiInner, EthApi};
4use alloy_network::Ethereum;
5use reth_chain_state::CanonStateSubscriptions;
6use reth_chainspec::ChainSpecProvider;
7use reth_primitives_traits::HeaderTy;
8use reth_rpc_convert::{RpcConvert, RpcConverter};
9use reth_rpc_eth_api::{
10    helpers::pending_block::PendingEnvBuilder, node::RpcNodeCoreAdapter, RpcNodeCore,
11};
12use reth_rpc_eth_types::{
13    builder::config::PendingBlockKind, fee_history::fee_history_cache_new_blocks_task,
14    receipt::EthReceiptConverter, EthStateCache, EthStateCacheConfig, FeeHistoryCache,
15    FeeHistoryCacheConfig, ForwardConfig, GasCap, GasPriceOracle, GasPriceOracleConfig,
16};
17use reth_rpc_server_types::constants::{
18    DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_PROOF_PERMITS,
19};
20use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
21use std::sync::Arc;
22
23/// A helper to build the `EthApi` handler instance.
24///
25/// This builder type contains all settings to create an [`EthApiInner`] or an [`EthApi`] instance
26/// directly.
27#[derive(Debug)]
28pub struct EthApiBuilder<N: RpcNodeCore, Rpc, NextEnv = ()> {
29    components: N,
30    rpc_converter: Rpc,
31    gas_cap: GasCap,
32    max_simulate_blocks: u64,
33    eth_proof_window: u64,
34    fee_history_cache_config: FeeHistoryCacheConfig,
35    proof_permits: usize,
36    eth_state_cache_config: EthStateCacheConfig,
37    eth_cache: Option<EthStateCache<N::Primitives>>,
38    gas_oracle_config: GasPriceOracleConfig,
39    gas_oracle: Option<GasPriceOracle<N::Provider>>,
40    blocking_task_pool: Option<BlockingTaskPool>,
41    task_spawner: Box<dyn TaskSpawner + 'static>,
42    next_env: NextEnv,
43    max_batch_size: usize,
44    pending_block_kind: PendingBlockKind,
45    raw_tx_forwarder: ForwardConfig,
46}
47
48impl<Provider, Pool, Network, EvmConfig, ChainSpec>
49    EthApiBuilder<
50        RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
51        RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
52    >
53where
54    RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
55        RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
56{
57    /// Creates a new `EthApiBuilder` instance.
58    pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
59        Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
60    }
61}
62
63impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
64    /// Converts the RPC converter type of this builder
65    pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
66    where
67        F: FnOnce(Rpc) -> R,
68    {
69        let Self {
70            components,
71            rpc_converter,
72            gas_cap,
73            max_simulate_blocks,
74            eth_proof_window,
75            fee_history_cache_config,
76            proof_permits,
77            eth_state_cache_config,
78            eth_cache,
79            gas_oracle_config,
80            gas_oracle,
81            blocking_task_pool,
82            task_spawner,
83            next_env,
84            max_batch_size,
85            pending_block_kind,
86            raw_tx_forwarder,
87        } = self;
88        EthApiBuilder {
89            components,
90            rpc_converter: f(rpc_converter),
91            gas_cap,
92            max_simulate_blocks,
93            eth_proof_window,
94            fee_history_cache_config,
95            proof_permits,
96            eth_state_cache_config,
97            eth_cache,
98            gas_oracle_config,
99            gas_oracle,
100            blocking_task_pool,
101            task_spawner,
102            next_env,
103            max_batch_size,
104            pending_block_kind,
105            raw_tx_forwarder,
106        }
107    }
108}
109
110impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
111where
112    N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
113{
114    /// Creates a new `EthApiBuilder` instance with the provided components.
115    pub fn new_with_components(components: N) -> Self {
116        let rpc_converter =
117            RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
118        Self {
119            components,
120            rpc_converter,
121            eth_cache: None,
122            gas_oracle: None,
123            gas_cap: GasCap::default(),
124            max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
125            eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
126            blocking_task_pool: None,
127            fee_history_cache_config: FeeHistoryCacheConfig::default(),
128            proof_permits: DEFAULT_PROOF_PERMITS,
129            task_spawner: TokioTaskExecutor::default().boxed(),
130            gas_oracle_config: Default::default(),
131            eth_state_cache_config: Default::default(),
132            next_env: Default::default(),
133            max_batch_size: 1,
134            pending_block_kind: PendingBlockKind::Full,
135            raw_tx_forwarder: ForwardConfig::default(),
136        }
137    }
138}
139
140impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
141where
142    N: RpcNodeCore,
143{
144    /// Configures the task spawner used to spawn additional tasks.
145    pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
146        self.task_spawner = Box::new(spawner);
147        self
148    }
149
150    /// Changes the configured converter.
151    pub fn with_rpc_converter<RpcNew>(
152        self,
153        rpc_converter: RpcNew,
154    ) -> EthApiBuilder<N, RpcNew, NextEnv> {
155        let Self {
156            components,
157            rpc_converter: _,
158            gas_cap,
159            max_simulate_blocks,
160            eth_proof_window,
161            fee_history_cache_config,
162            proof_permits,
163            eth_state_cache_config,
164            eth_cache,
165            gas_oracle,
166            blocking_task_pool,
167            task_spawner,
168            gas_oracle_config,
169            next_env,
170            max_batch_size,
171            pending_block_kind,
172            raw_tx_forwarder,
173        } = self;
174        EthApiBuilder {
175            components,
176            rpc_converter,
177            gas_cap,
178            max_simulate_blocks,
179            eth_proof_window,
180            fee_history_cache_config,
181            proof_permits,
182            eth_state_cache_config,
183            eth_cache,
184            gas_oracle,
185            blocking_task_pool,
186            task_spawner,
187            gas_oracle_config,
188            next_env,
189            max_batch_size,
190            pending_block_kind,
191            raw_tx_forwarder,
192        }
193    }
194
195    /// Changes the configured pending environment builder.
196    pub fn with_pending_env_builder<NextEnvNew>(
197        self,
198        next_env: NextEnvNew,
199    ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
200        let Self {
201            components,
202            rpc_converter,
203            gas_cap,
204            max_simulate_blocks,
205            eth_proof_window,
206            fee_history_cache_config,
207            proof_permits,
208            eth_state_cache_config,
209            eth_cache,
210            gas_oracle,
211            blocking_task_pool,
212            task_spawner,
213            gas_oracle_config,
214            next_env: _,
215            max_batch_size,
216            pending_block_kind,
217            raw_tx_forwarder,
218        } = self;
219        EthApiBuilder {
220            components,
221            rpc_converter,
222            gas_cap,
223            max_simulate_blocks,
224            eth_proof_window,
225            fee_history_cache_config,
226            proof_permits,
227            eth_state_cache_config,
228            eth_cache,
229            gas_oracle,
230            blocking_task_pool,
231            task_spawner,
232            gas_oracle_config,
233            next_env,
234            max_batch_size,
235            pending_block_kind,
236            raw_tx_forwarder,
237        }
238    }
239
240    /// Sets `eth_cache` config for the cache that will be used if no [`EthStateCache`] is
241    /// configured.
242    pub const fn eth_state_cache_config(
243        mut self,
244        eth_state_cache_config: EthStateCacheConfig,
245    ) -> Self {
246        self.eth_state_cache_config = eth_state_cache_config;
247        self
248    }
249
250    /// Sets `eth_cache` instance
251    pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
252        self.eth_cache = Some(eth_cache);
253        self
254    }
255
256    /// Sets `gas_oracle` config for the gas oracle that will be used if no [`GasPriceOracle`] is
257    /// configured.
258    pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
259        self.gas_oracle_config = gas_oracle_config;
260        self
261    }
262
263    /// Sets `gas_oracle` instance
264    pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
265        self.gas_oracle = Some(gas_oracle);
266        self
267    }
268
269    /// Sets the gas cap.
270    pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
271        self.gas_cap = gas_cap;
272        self
273    }
274
275    /// Sets the maximum number of blocks for `eth_simulateV1`.
276    pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
277        self.max_simulate_blocks = max_simulate_blocks;
278        self
279    }
280
281    /// Sets the maximum number of blocks into the past for generating state proofs.
282    pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
283        self.eth_proof_window = eth_proof_window;
284        self
285    }
286
287    /// Sets the blocking task pool.
288    pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
289        self.blocking_task_pool = Some(blocking_task_pool);
290        self
291    }
292
293    /// Sets the fee history cache.
294    pub const fn fee_history_cache_config(
295        mut self,
296        fee_history_cache_config: FeeHistoryCacheConfig,
297    ) -> Self {
298        self.fee_history_cache_config = fee_history_cache_config;
299        self
300    }
301
302    /// Sets the proof permits.
303    pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
304        self.proof_permits = proof_permits;
305        self
306    }
307
308    /// Sets the max batch size for batching transaction insertions.
309    pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
310        self.max_batch_size = max_batch_size;
311        self
312    }
313
314    /// Sets the pending block kind
315    pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
316        self.pending_block_kind = pending_block_kind;
317        self
318    }
319
320    /// Sets the raw transaction forwarder.
321    pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
322        self.raw_tx_forwarder = tx_forwarder;
323        self
324    }
325
326    /// Builds the [`EthApiInner`] instance.
327    ///
328    /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`].
329    ///
330    /// # Panics
331    ///
332    /// This function panics if the blocking task pool cannot be built.
333    /// This will panic if called outside the context of a Tokio runtime.
334    pub fn build_inner(self) -> EthApiInner<N, Rpc>
335    where
336        Rpc: RpcConvert,
337        NextEnv: PendingEnvBuilder<N::Evm>,
338    {
339        let Self {
340            components,
341            rpc_converter,
342            eth_state_cache_config,
343            gas_oracle_config,
344            eth_cache,
345            gas_oracle,
346            gas_cap,
347            max_simulate_blocks,
348            eth_proof_window,
349            blocking_task_pool,
350            fee_history_cache_config,
351            proof_permits,
352            task_spawner,
353            next_env,
354            max_batch_size,
355            pending_block_kind,
356            raw_tx_forwarder,
357        } = self;
358
359        let provider = components.provider().clone();
360
361        let eth_cache = eth_cache
362            .unwrap_or_else(|| EthStateCache::spawn(provider.clone(), eth_state_cache_config));
363        let gas_oracle = gas_oracle.unwrap_or_else(|| {
364            GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
365        });
366        let fee_history_cache =
367            FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
368        let new_canonical_blocks = provider.canonical_state_stream();
369        let fhc = fee_history_cache.clone();
370        let cache = eth_cache.clone();
371        task_spawner.spawn_critical(
372            "cache canonical blocks for fee history task",
373            Box::pin(async move {
374                fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
375            }),
376        );
377
378        EthApiInner::new(
379            components,
380            eth_cache,
381            gas_oracle,
382            gas_cap,
383            max_simulate_blocks,
384            eth_proof_window,
385            blocking_task_pool.unwrap_or_else(|| {
386                BlockingTaskPool::build().expect("failed to build blocking task pool")
387            }),
388            fee_history_cache,
389            task_spawner,
390            proof_permits,
391            rpc_converter,
392            next_env,
393            max_batch_size,
394            pending_block_kind,
395            raw_tx_forwarder.forwarder_client(),
396        )
397    }
398
399    /// Builds the [`EthApi`] instance.
400    ///
401    /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`].
402    ///
403    /// # Panics
404    ///
405    /// This function panics if the blocking task pool cannot be built.
406    /// This will panic if called outside the context of a Tokio runtime.
407    pub fn build(self) -> EthApi<N, Rpc>
408    where
409        Rpc: RpcConvert,
410        NextEnv: PendingEnvBuilder<N::Evm>,
411    {
412        EthApi { inner: Arc::new(self.build_inner()) }
413    }
414}