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, time::Duration};
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 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 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 pub fn apply<F>(self, f: F) -> Self
68 where
69 F: FnOnce(Self) -> Self,
70 {
71 f(self)
72 }
73
74 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 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 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
162 self.task_spawner = Box::new(spawner);
163 self
164 }
165
166 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 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 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 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
276 self.eth_cache = Some(eth_cache);
277 self
278 }
279
280 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 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
289 self.gas_oracle = Some(gas_oracle);
290 self
291 }
292
293 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
295 self.gas_cap = gas_cap;
296 self
297 }
298
299 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 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 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 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 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
328 self.proof_permits = proof_permits;
329 self
330 }
331
332 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 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 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
346 self.raw_tx_forwarder = tx_forwarder;
347 self
348 }
349
350 pub const fn get_gas_cap(&self) -> &GasCap {
352 &self.gas_cap
353 }
354
355 pub const fn get_max_simulate_blocks(&self) -> u64 {
357 self.max_simulate_blocks
358 }
359
360 pub const fn get_eth_proof_window(&self) -> u64 {
362 self.eth_proof_window
363 }
364
365 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
367 &self.fee_history_cache_config
368 }
369
370 pub const fn get_proof_permits(&self) -> usize {
372 self.proof_permits
373 }
374
375 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
377 &self.eth_state_cache_config
378 }
379
380 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
382 &self.gas_oracle_config
383 }
384
385 pub const fn get_max_batch_size(&self) -> usize {
387 self.max_batch_size
388 }
389
390 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
392 self.pending_block_kind
393 }
394
395 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
397 &self.raw_tx_forwarder
398 }
399
400 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
402 &mut self.fee_history_cache_config
403 }
404
405 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
407 &mut self.eth_state_cache_config
408 }
409
410 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
412 &mut self.gas_oracle_config
413 }
414
415 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
417 &mut self.raw_tx_forwarder
418 }
419
420 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 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 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 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 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 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 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 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
557 self.evm_memory_limit = memory_limit;
558 self
559 }
560}