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_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#[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 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 pub fn apply<F>(self, f: F) -> Self
71 where
72 F: FnOnce(Self) -> Self,
73 {
74 f(self)
75 }
76
77 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 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 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
171 self.task_spawner = Box::new(spawner);
172 self
173 }
174
175 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 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 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 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
293 self.eth_cache = Some(eth_cache);
294 self
295 }
296
297 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 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
306 self.gas_oracle = Some(gas_oracle);
307 self
308 }
309
310 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
312 self.gas_cap = gas_cap;
313 self
314 }
315
316 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 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 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 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 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
345 self.proof_permits = proof_permits;
346 self
347 }
348
349 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 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 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 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
369 self.raw_tx_forwarder = tx_forwarder;
370 self
371 }
372
373 pub const fn get_gas_cap(&self) -> &GasCap {
375 &self.gas_cap
376 }
377
378 pub const fn get_max_simulate_blocks(&self) -> u64 {
380 self.max_simulate_blocks
381 }
382
383 pub const fn get_eth_proof_window(&self) -> u64 {
385 self.eth_proof_window
386 }
387
388 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
390 &self.fee_history_cache_config
391 }
392
393 pub const fn get_proof_permits(&self) -> usize {
395 self.proof_permits
396 }
397
398 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
400 &self.eth_state_cache_config
401 }
402
403 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
405 &self.gas_oracle_config
406 }
407
408 pub const fn get_max_batch_size(&self) -> usize {
410 self.max_batch_size
411 }
412
413 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
415 self.pending_block_kind
416 }
417
418 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
420 &self.raw_tx_forwarder
421 }
422
423 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
425 &mut self.fee_history_cache_config
426 }
427
428 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
430 &mut self.eth_state_cache_config
431 }
432
433 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
435 &mut self.gas_oracle_config
436 }
437
438 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
440 &mut self.raw_tx_forwarder
441 }
442
443 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 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 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 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 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 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 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 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
588 self.evm_memory_limit = memory_limit;
589 self
590 }
591
592 pub const fn force_blob_sidecar_upcasting(mut self, force: bool) -> Self {
594 self.force_blob_sidecar_upcasting = force;
595 self
596 }
597}