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_BLOCKING_IO_REQUEST, DEFAULT_MAX_SIMULATE_BLOCKS,
19    DEFAULT_PROOF_PERMITS,
20};
21use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
22use std::{sync::Arc, time::Duration};
23
24/// A helper to build the `EthApi` handler instance.
25///
26/// This builder type contains all settings to create an [`EthApiInner`] or an [`EthApi`] instance
27/// directly.
28#[derive(Debug)]
29pub struct EthApiBuilder<N: RpcNodeCore, Rpc, NextEnv = ()> {
30    components: N,
31    rpc_converter: Rpc,
32    gas_cap: GasCap,
33    max_simulate_blocks: u64,
34    eth_proof_window: u64,
35    fee_history_cache_config: FeeHistoryCacheConfig,
36    proof_permits: usize,
37    eth_state_cache_config: EthStateCacheConfig,
38    eth_cache: Option<EthStateCache<N::Primitives>>,
39    gas_oracle_config: GasPriceOracleConfig,
40    gas_oracle: Option<GasPriceOracle<N::Provider>>,
41    blocking_task_pool: Option<BlockingTaskPool>,
42    task_spawner: Box<dyn TaskSpawner + 'static>,
43    next_env: NextEnv,
44    max_batch_size: usize,
45    max_blocking_io_requests: usize,
46    pending_block_kind: PendingBlockKind,
47    raw_tx_forwarder: ForwardConfig,
48    send_raw_transaction_sync_timeout: Duration,
49    evm_memory_limit: u64,
50}
51
52impl<Provider, Pool, Network, EvmConfig, ChainSpec>
53    EthApiBuilder<
54        RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
55        RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
56    >
57where
58    RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
59        RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
60{
61    /// Creates a new `EthApiBuilder` instance.
62    pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
63        Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
64    }
65}
66
67impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
68    /// Apply a function to the builder
69    pub fn apply<F>(self, f: F) -> Self
70    where
71        F: FnOnce(Self) -> Self,
72    {
73        f(self)
74    }
75
76    /// Converts the RPC converter type of this builder
77    pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
78    where
79        F: FnOnce(Rpc) -> R,
80    {
81        let Self {
82            components,
83            rpc_converter,
84            gas_cap,
85            max_simulate_blocks,
86            eth_proof_window,
87            fee_history_cache_config,
88            proof_permits,
89            eth_state_cache_config,
90            eth_cache,
91            gas_oracle_config,
92            gas_oracle,
93            blocking_task_pool,
94            task_spawner,
95            next_env,
96            max_batch_size,
97            max_blocking_io_requests,
98            pending_block_kind,
99            raw_tx_forwarder,
100            send_raw_transaction_sync_timeout,
101            evm_memory_limit,
102        } = self;
103        EthApiBuilder {
104            components,
105            rpc_converter: f(rpc_converter),
106            gas_cap,
107            max_simulate_blocks,
108            eth_proof_window,
109            fee_history_cache_config,
110            proof_permits,
111            eth_state_cache_config,
112            eth_cache,
113            gas_oracle_config,
114            gas_oracle,
115            blocking_task_pool,
116            task_spawner,
117            next_env,
118            max_batch_size,
119            max_blocking_io_requests,
120            pending_block_kind,
121            raw_tx_forwarder,
122            send_raw_transaction_sync_timeout,
123            evm_memory_limit,
124        }
125    }
126}
127
128impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
129where
130    N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
131{
132    /// Creates a new `EthApiBuilder` instance with the provided components.
133    pub fn new_with_components(components: N) -> Self {
134        let rpc_converter =
135            RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
136        Self {
137            components,
138            rpc_converter,
139            eth_cache: None,
140            gas_oracle: None,
141            gas_cap: GasCap::default(),
142            max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
143            eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
144            blocking_task_pool: None,
145            fee_history_cache_config: FeeHistoryCacheConfig::default(),
146            proof_permits: DEFAULT_PROOF_PERMITS,
147            task_spawner: TokioTaskExecutor::default().boxed(),
148            gas_oracle_config: Default::default(),
149            eth_state_cache_config: Default::default(),
150            next_env: Default::default(),
151            max_batch_size: 1,
152            max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
153            pending_block_kind: PendingBlockKind::Full,
154            raw_tx_forwarder: ForwardConfig::default(),
155            send_raw_transaction_sync_timeout: Duration::from_secs(30),
156            evm_memory_limit: (1 << 32) - 1,
157        }
158    }
159}
160
161impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
162where
163    N: RpcNodeCore,
164{
165    /// Configures the task spawner used to spawn additional tasks.
166    pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
167        self.task_spawner = Box::new(spawner);
168        self
169    }
170
171    /// Changes the configured converter.
172    pub fn with_rpc_converter<RpcNew>(
173        self,
174        rpc_converter: RpcNew,
175    ) -> EthApiBuilder<N, RpcNew, NextEnv> {
176        let Self {
177            components,
178            rpc_converter: _,
179            gas_cap,
180            max_simulate_blocks,
181            eth_proof_window,
182            fee_history_cache_config,
183            proof_permits,
184            eth_state_cache_config,
185            eth_cache,
186            gas_oracle,
187            blocking_task_pool,
188            task_spawner,
189            gas_oracle_config,
190            next_env,
191            max_batch_size,
192            max_blocking_io_requests,
193            pending_block_kind,
194            raw_tx_forwarder,
195            send_raw_transaction_sync_timeout,
196            evm_memory_limit,
197        } = self;
198        EthApiBuilder {
199            components,
200            rpc_converter,
201            gas_cap,
202            max_simulate_blocks,
203            eth_proof_window,
204            fee_history_cache_config,
205            proof_permits,
206            eth_state_cache_config,
207            eth_cache,
208            gas_oracle,
209            blocking_task_pool,
210            task_spawner,
211            gas_oracle_config,
212            next_env,
213            max_batch_size,
214            max_blocking_io_requests,
215            pending_block_kind,
216            raw_tx_forwarder,
217            send_raw_transaction_sync_timeout,
218            evm_memory_limit,
219        }
220    }
221
222    /// Changes the configured pending environment builder.
223    pub fn with_pending_env_builder<NextEnvNew>(
224        self,
225        next_env: NextEnvNew,
226    ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
227        let Self {
228            components,
229            rpc_converter,
230            gas_cap,
231            max_simulate_blocks,
232            eth_proof_window,
233            fee_history_cache_config,
234            proof_permits,
235            eth_state_cache_config,
236            eth_cache,
237            gas_oracle,
238            blocking_task_pool,
239            task_spawner,
240            gas_oracle_config,
241            next_env: _,
242            max_batch_size,
243            max_blocking_io_requests,
244            pending_block_kind,
245            raw_tx_forwarder,
246            send_raw_transaction_sync_timeout,
247            evm_memory_limit,
248        } = self;
249        EthApiBuilder {
250            components,
251            rpc_converter,
252            gas_cap,
253            max_simulate_blocks,
254            eth_proof_window,
255            fee_history_cache_config,
256            proof_permits,
257            eth_state_cache_config,
258            eth_cache,
259            gas_oracle,
260            blocking_task_pool,
261            task_spawner,
262            gas_oracle_config,
263            next_env,
264            max_batch_size,
265            max_blocking_io_requests,
266            pending_block_kind,
267            raw_tx_forwarder,
268            send_raw_transaction_sync_timeout,
269            evm_memory_limit,
270        }
271    }
272
273    /// Sets `eth_cache` config for the cache that will be used if no [`EthStateCache`] is
274    /// configured.
275    pub const fn eth_state_cache_config(
276        mut self,
277        eth_state_cache_config: EthStateCacheConfig,
278    ) -> Self {
279        self.eth_state_cache_config = eth_state_cache_config;
280        self
281    }
282
283    /// Sets `eth_cache` instance
284    pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
285        self.eth_cache = Some(eth_cache);
286        self
287    }
288
289    /// Sets `gas_oracle` config for the gas oracle that will be used if no [`GasPriceOracle`] is
290    /// configured.
291    pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
292        self.gas_oracle_config = gas_oracle_config;
293        self
294    }
295
296    /// Sets `gas_oracle` instance
297    pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
298        self.gas_oracle = Some(gas_oracle);
299        self
300    }
301
302    /// Sets the gas cap.
303    pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
304        self.gas_cap = gas_cap;
305        self
306    }
307
308    /// Sets the maximum number of blocks for `eth_simulateV1`.
309    pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
310        self.max_simulate_blocks = max_simulate_blocks;
311        self
312    }
313
314    /// Sets the maximum number of blocks into the past for generating state proofs.
315    pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
316        self.eth_proof_window = eth_proof_window;
317        self
318    }
319
320    /// Sets the blocking task pool.
321    pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
322        self.blocking_task_pool = Some(blocking_task_pool);
323        self
324    }
325
326    /// Sets the fee history cache.
327    pub const fn fee_history_cache_config(
328        mut self,
329        fee_history_cache_config: FeeHistoryCacheConfig,
330    ) -> Self {
331        self.fee_history_cache_config = fee_history_cache_config;
332        self
333    }
334
335    /// Sets the proof permits.
336    pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
337        self.proof_permits = proof_permits;
338        self
339    }
340
341    /// Sets the max batch size for batching transaction insertions.
342    pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
343        self.max_batch_size = max_batch_size;
344        self
345    }
346
347    /// Sets the maximum number of concurrent blocking IO requests.
348    pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
349        self.max_blocking_io_requests = max_blocking_io_requests;
350        self
351    }
352
353    /// Sets the pending block kind
354    pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
355        self.pending_block_kind = pending_block_kind;
356        self
357    }
358
359    /// Sets the raw transaction forwarder.
360    pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
361        self.raw_tx_forwarder = tx_forwarder;
362        self
363    }
364
365    /// Returns the gas cap.
366    pub const fn get_gas_cap(&self) -> &GasCap {
367        &self.gas_cap
368    }
369
370    /// Returns the maximum simulate blocks.
371    pub const fn get_max_simulate_blocks(&self) -> u64 {
372        self.max_simulate_blocks
373    }
374
375    /// Returns the ETH proof window.
376    pub const fn get_eth_proof_window(&self) -> u64 {
377        self.eth_proof_window
378    }
379
380    /// Returns a reference to the fee history cache config.
381    pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
382        &self.fee_history_cache_config
383    }
384
385    /// Returns the proof permits.
386    pub const fn get_proof_permits(&self) -> usize {
387        self.proof_permits
388    }
389
390    /// Returns a reference to the ETH state cache config.
391    pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
392        &self.eth_state_cache_config
393    }
394
395    /// Returns a reference to the gas oracle config.
396    pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
397        &self.gas_oracle_config
398    }
399
400    /// Returns the max batch size.
401    pub const fn get_max_batch_size(&self) -> usize {
402        self.max_batch_size
403    }
404
405    /// Returns the pending block kind.
406    pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
407        self.pending_block_kind
408    }
409
410    /// Returns a reference to the raw tx forwarder config.
411    pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
412        &self.raw_tx_forwarder
413    }
414
415    /// Returns a mutable reference to the fee history cache config.
416    pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
417        &mut self.fee_history_cache_config
418    }
419
420    /// Returns a mutable reference to the ETH state cache config.
421    pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
422        &mut self.eth_state_cache_config
423    }
424
425    /// Returns a mutable reference to the gas oracle config.
426    pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
427        &mut self.gas_oracle_config
428    }
429
430    /// Returns a mutable reference to the raw tx forwarder config.
431    pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
432        &mut self.raw_tx_forwarder
433    }
434
435    /// Modifies the fee history cache configuration using a closure.
436    pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
437    where
438        F: FnOnce(&mut FeeHistoryCacheConfig),
439    {
440        f(&mut self.fee_history_cache_config);
441        self
442    }
443
444    /// Modifies the ETH state cache configuration using a closure.
445    pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
446    where
447        F: FnOnce(&mut EthStateCacheConfig),
448    {
449        f(&mut self.eth_state_cache_config);
450        self
451    }
452
453    /// Modifies the gas oracle configuration using a closure.
454    pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
455    where
456        F: FnOnce(&mut GasPriceOracleConfig),
457    {
458        f(&mut self.gas_oracle_config);
459        self
460    }
461
462    /// Modifies the raw tx forwarder configuration using a closure.
463    pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
464    where
465        F: FnOnce(&mut ForwardConfig),
466    {
467        f(&mut self.raw_tx_forwarder);
468        self
469    }
470
471    /// Builds the [`EthApiInner`] instance.
472    ///
473    /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`].
474    ///
475    /// # Panics
476    ///
477    /// This function panics if the blocking task pool cannot be built.
478    /// This will panic if called outside the context of a Tokio runtime.
479    pub fn build_inner(self) -> EthApiInner<N, Rpc>
480    where
481        Rpc: RpcConvert,
482        NextEnv: PendingEnvBuilder<N::Evm>,
483    {
484        let Self {
485            components,
486            rpc_converter,
487            eth_state_cache_config,
488            gas_oracle_config,
489            eth_cache,
490            gas_oracle,
491            gas_cap,
492            max_simulate_blocks,
493            eth_proof_window,
494            blocking_task_pool,
495            fee_history_cache_config,
496            proof_permits,
497            task_spawner,
498            next_env,
499            max_batch_size,
500            max_blocking_io_requests,
501            pending_block_kind,
502            raw_tx_forwarder,
503            send_raw_transaction_sync_timeout,
504            evm_memory_limit,
505        } = self;
506
507        let provider = components.provider().clone();
508
509        let eth_cache = eth_cache
510            .unwrap_or_else(|| EthStateCache::spawn(provider.clone(), eth_state_cache_config));
511        let gas_oracle = gas_oracle.unwrap_or_else(|| {
512            GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
513        });
514        let fee_history_cache =
515            FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
516        let new_canonical_blocks = provider.canonical_state_stream();
517        let fhc = fee_history_cache.clone();
518        let cache = eth_cache.clone();
519        task_spawner.spawn_critical(
520            "cache canonical blocks for fee history task",
521            Box::pin(async move {
522                fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
523            }),
524        );
525
526        EthApiInner::new(
527            components,
528            eth_cache,
529            gas_oracle,
530            gas_cap,
531            max_simulate_blocks,
532            eth_proof_window,
533            blocking_task_pool.unwrap_or_else(|| {
534                BlockingTaskPool::build().expect("failed to build blocking task pool")
535            }),
536            fee_history_cache,
537            task_spawner,
538            proof_permits,
539            rpc_converter,
540            next_env,
541            max_batch_size,
542            max_blocking_io_requests,
543            pending_block_kind,
544            raw_tx_forwarder.forwarder_client(),
545            send_raw_transaction_sync_timeout,
546            evm_memory_limit,
547        )
548    }
549
550    /// Builds the [`EthApi`] instance.
551    ///
552    /// If not configured, this will spawn the cache backend: [`EthStateCache::spawn`].
553    ///
554    /// # Panics
555    ///
556    /// This function panics if the blocking task pool cannot be built.
557    /// This will panic if called outside the context of a Tokio runtime.
558    pub fn build(self) -> EthApi<N, Rpc>
559    where
560        Rpc: RpcConvert,
561        NextEnv: PendingEnvBuilder<N::Evm>,
562    {
563        EthApi { inner: Arc::new(self.build_inner()) }
564    }
565
566    /// Sets the timeout for `send_raw_transaction_sync` RPC method.
567    pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
568        self.send_raw_transaction_sync_timeout = timeout;
569        self
570    }
571
572    /// Sets the maximum memory the EVM can allocate per RPC request.
573    pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
574        self.evm_memory_limit = memory_limit;
575        self
576    }
577}