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