Skip to main content

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