1use 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#[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 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 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 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 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
146 self.task_spawner = Box::new(spawner);
147 self
148 }
149
150 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 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 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 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
252 self.eth_cache = Some(eth_cache);
253 self
254 }
255
256 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 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
265 self.gas_oracle = Some(gas_oracle);
266 self
267 }
268
269 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
271 self.gas_cap = gas_cap;
272 self
273 }
274
275 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 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 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 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 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
304 self.proof_permits = proof_permits;
305 self
306 }
307
308 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 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 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
322 self.raw_tx_forwarder = tx_forwarder;
323 self
324 }
325
326 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 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}