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