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}
48
49impl<Provider, Pool, Network, EvmConfig, ChainSpec>
50 EthApiBuilder<
51 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
52 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
53 >
54where
55 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
56 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
57{
58 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
60 Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
61 }
62}
63
64impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
65 pub fn apply<F>(self, f: F) -> Self
67 where
68 F: FnOnce(Self) -> Self,
69 {
70 f(self)
71 }
72
73 pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
75 where
76 F: FnOnce(Rpc) -> R,
77 {
78 let Self {
79 components,
80 rpc_converter,
81 gas_cap,
82 max_simulate_blocks,
83 eth_proof_window,
84 fee_history_cache_config,
85 proof_permits,
86 eth_state_cache_config,
87 eth_cache,
88 gas_oracle_config,
89 gas_oracle,
90 blocking_task_pool,
91 task_spawner,
92 next_env,
93 max_batch_size,
94 pending_block_kind,
95 raw_tx_forwarder,
96 send_raw_transaction_sync_timeout,
97 } = self;
98 EthApiBuilder {
99 components,
100 rpc_converter: f(rpc_converter),
101 gas_cap,
102 max_simulate_blocks,
103 eth_proof_window,
104 fee_history_cache_config,
105 proof_permits,
106 eth_state_cache_config,
107 eth_cache,
108 gas_oracle_config,
109 gas_oracle,
110 blocking_task_pool,
111 task_spawner,
112 next_env,
113 max_batch_size,
114 pending_block_kind,
115 raw_tx_forwarder,
116 send_raw_transaction_sync_timeout,
117 }
118 }
119}
120
121impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
122where
123 N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
124{
125 pub fn new_with_components(components: N) -> Self {
127 let rpc_converter =
128 RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
129 Self {
130 components,
131 rpc_converter,
132 eth_cache: None,
133 gas_oracle: None,
134 gas_cap: GasCap::default(),
135 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
136 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
137 blocking_task_pool: None,
138 fee_history_cache_config: FeeHistoryCacheConfig::default(),
139 proof_permits: DEFAULT_PROOF_PERMITS,
140 task_spawner: TokioTaskExecutor::default().boxed(),
141 gas_oracle_config: Default::default(),
142 eth_state_cache_config: Default::default(),
143 next_env: Default::default(),
144 max_batch_size: 1,
145 pending_block_kind: PendingBlockKind::Full,
146 raw_tx_forwarder: ForwardConfig::default(),
147 send_raw_transaction_sync_timeout: Duration::from_secs(30),
148 }
149 }
150}
151
152impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
153where
154 N: RpcNodeCore,
155{
156 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
158 self.task_spawner = Box::new(spawner);
159 self
160 }
161
162 pub fn with_rpc_converter<RpcNew>(
164 self,
165 rpc_converter: RpcNew,
166 ) -> EthApiBuilder<N, RpcNew, NextEnv> {
167 let Self {
168 components,
169 rpc_converter: _,
170 gas_cap,
171 max_simulate_blocks,
172 eth_proof_window,
173 fee_history_cache_config,
174 proof_permits,
175 eth_state_cache_config,
176 eth_cache,
177 gas_oracle,
178 blocking_task_pool,
179 task_spawner,
180 gas_oracle_config,
181 next_env,
182 max_batch_size,
183 pending_block_kind,
184 raw_tx_forwarder,
185 send_raw_transaction_sync_timeout,
186 } = self;
187 EthApiBuilder {
188 components,
189 rpc_converter,
190 gas_cap,
191 max_simulate_blocks,
192 eth_proof_window,
193 fee_history_cache_config,
194 proof_permits,
195 eth_state_cache_config,
196 eth_cache,
197 gas_oracle,
198 blocking_task_pool,
199 task_spawner,
200 gas_oracle_config,
201 next_env,
202 max_batch_size,
203 pending_block_kind,
204 raw_tx_forwarder,
205 send_raw_transaction_sync_timeout,
206 }
207 }
208
209 pub fn with_pending_env_builder<NextEnvNew>(
211 self,
212 next_env: NextEnvNew,
213 ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
214 let Self {
215 components,
216 rpc_converter,
217 gas_cap,
218 max_simulate_blocks,
219 eth_proof_window,
220 fee_history_cache_config,
221 proof_permits,
222 eth_state_cache_config,
223 eth_cache,
224 gas_oracle,
225 blocking_task_pool,
226 task_spawner,
227 gas_oracle_config,
228 next_env: _,
229 max_batch_size,
230 pending_block_kind,
231 raw_tx_forwarder,
232 send_raw_transaction_sync_timeout,
233 } = self;
234 EthApiBuilder {
235 components,
236 rpc_converter,
237 gas_cap,
238 max_simulate_blocks,
239 eth_proof_window,
240 fee_history_cache_config,
241 proof_permits,
242 eth_state_cache_config,
243 eth_cache,
244 gas_oracle,
245 blocking_task_pool,
246 task_spawner,
247 gas_oracle_config,
248 next_env,
249 max_batch_size,
250 pending_block_kind,
251 raw_tx_forwarder,
252 send_raw_transaction_sync_timeout,
253 }
254 }
255
256 pub const fn eth_state_cache_config(
259 mut self,
260 eth_state_cache_config: EthStateCacheConfig,
261 ) -> Self {
262 self.eth_state_cache_config = eth_state_cache_config;
263 self
264 }
265
266 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
268 self.eth_cache = Some(eth_cache);
269 self
270 }
271
272 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
275 self.gas_oracle_config = gas_oracle_config;
276 self
277 }
278
279 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
281 self.gas_oracle = Some(gas_oracle);
282 self
283 }
284
285 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
287 self.gas_cap = gas_cap;
288 self
289 }
290
291 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
293 self.max_simulate_blocks = max_simulate_blocks;
294 self
295 }
296
297 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
299 self.eth_proof_window = eth_proof_window;
300 self
301 }
302
303 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
305 self.blocking_task_pool = Some(blocking_task_pool);
306 self
307 }
308
309 pub const fn fee_history_cache_config(
311 mut self,
312 fee_history_cache_config: FeeHistoryCacheConfig,
313 ) -> Self {
314 self.fee_history_cache_config = fee_history_cache_config;
315 self
316 }
317
318 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
320 self.proof_permits = proof_permits;
321 self
322 }
323
324 pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
326 self.max_batch_size = max_batch_size;
327 self
328 }
329
330 pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
332 self.pending_block_kind = pending_block_kind;
333 self
334 }
335
336 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
338 self.raw_tx_forwarder = tx_forwarder;
339 self
340 }
341
342 pub const fn get_gas_cap(&self) -> &GasCap {
344 &self.gas_cap
345 }
346
347 pub const fn get_max_simulate_blocks(&self) -> u64 {
349 self.max_simulate_blocks
350 }
351
352 pub const fn get_eth_proof_window(&self) -> u64 {
354 self.eth_proof_window
355 }
356
357 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
359 &self.fee_history_cache_config
360 }
361
362 pub const fn get_proof_permits(&self) -> usize {
364 self.proof_permits
365 }
366
367 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
369 &self.eth_state_cache_config
370 }
371
372 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
374 &self.gas_oracle_config
375 }
376
377 pub const fn get_max_batch_size(&self) -> usize {
379 self.max_batch_size
380 }
381
382 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
384 self.pending_block_kind
385 }
386
387 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
389 &self.raw_tx_forwarder
390 }
391
392 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
394 &mut self.fee_history_cache_config
395 }
396
397 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
399 &mut self.eth_state_cache_config
400 }
401
402 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
404 &mut self.gas_oracle_config
405 }
406
407 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
409 &mut self.raw_tx_forwarder
410 }
411
412 pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
414 where
415 F: FnOnce(&mut FeeHistoryCacheConfig),
416 {
417 f(&mut self.fee_history_cache_config);
418 self
419 }
420
421 pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
423 where
424 F: FnOnce(&mut EthStateCacheConfig),
425 {
426 f(&mut self.eth_state_cache_config);
427 self
428 }
429
430 pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
432 where
433 F: FnOnce(&mut GasPriceOracleConfig),
434 {
435 f(&mut self.gas_oracle_config);
436 self
437 }
438
439 pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
441 where
442 F: FnOnce(&mut ForwardConfig),
443 {
444 f(&mut self.raw_tx_forwarder);
445 self
446 }
447
448 pub fn build_inner(self) -> EthApiInner<N, Rpc>
457 where
458 Rpc: RpcConvert,
459 NextEnv: PendingEnvBuilder<N::Evm>,
460 {
461 let Self {
462 components,
463 rpc_converter,
464 eth_state_cache_config,
465 gas_oracle_config,
466 eth_cache,
467 gas_oracle,
468 gas_cap,
469 max_simulate_blocks,
470 eth_proof_window,
471 blocking_task_pool,
472 fee_history_cache_config,
473 proof_permits,
474 task_spawner,
475 next_env,
476 max_batch_size,
477 pending_block_kind,
478 raw_tx_forwarder,
479 send_raw_transaction_sync_timeout,
480 } = self;
481
482 let provider = components.provider().clone();
483
484 let eth_cache = eth_cache
485 .unwrap_or_else(|| EthStateCache::spawn(provider.clone(), eth_state_cache_config));
486 let gas_oracle = gas_oracle.unwrap_or_else(|| {
487 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
488 });
489 let fee_history_cache =
490 FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
491 let new_canonical_blocks = provider.canonical_state_stream();
492 let fhc = fee_history_cache.clone();
493 let cache = eth_cache.clone();
494 task_spawner.spawn_critical(
495 "cache canonical blocks for fee history task",
496 Box::pin(async move {
497 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
498 }),
499 );
500
501 EthApiInner::new(
502 components,
503 eth_cache,
504 gas_oracle,
505 gas_cap,
506 max_simulate_blocks,
507 eth_proof_window,
508 blocking_task_pool.unwrap_or_else(|| {
509 BlockingTaskPool::build().expect("failed to build blocking task pool")
510 }),
511 fee_history_cache,
512 task_spawner,
513 proof_permits,
514 rpc_converter,
515 next_env,
516 max_batch_size,
517 pending_block_kind,
518 raw_tx_forwarder.forwarder_client(),
519 send_raw_transaction_sync_timeout,
520 )
521 }
522
523 pub fn build(self) -> EthApi<N, Rpc>
532 where
533 Rpc: RpcConvert,
534 NextEnv: PendingEnvBuilder<N::Evm>,
535 {
536 EthApi { inner: Arc::new(self.build_inner()) }
537 }
538
539 pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
541 self.send_raw_transaction_sync_timeout = timeout;
542 self
543 }
544}