1use crate::{eth::core::EthApiInner, EthApi};
4use alloy_network::Ethereum;
5use reth_chain_state::CanonStateSubscriptions;
6use reth_chainspec::ChainSpecProvider;
7use reth_evm::SenderRecoveryCache;
8use reth_primitives_traits::HeaderTy;
9use reth_rpc_convert::{RpcConvert, RpcConverter};
10use reth_rpc_eth_api::{
11 helpers::pending_block::PendingEnvBuilder, node::RpcNodeCoreAdapter, RpcNodeCore,
12};
13use reth_rpc_eth_types::{
14 builder::config::PendingBlockKind, fee_history::fee_history_cache_new_blocks_task,
15 receipt::EthReceiptConverter, EthApiSettings, EthStateCache, EthStateCacheConfig,
16 FeeHistoryCache, FeeHistoryCacheConfig, ForwardConfig, GasCap, GasPriceOracle,
17 GasPriceOracleConfig,
18};
19use reth_rpc_server_types::constants::{
20 DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_BLOCKING_IO_REQUEST, DEFAULT_MAX_SIMULATE_BLOCKS,
21 DEFAULT_PROOF_PERMITS,
22};
23use reth_tasks::{pool::BlockingTaskPool, Runtime};
24use std::{sync::Arc, time::Duration};
25
26#[derive(Debug)]
31pub struct EthApiBuilder<N: RpcNodeCore, Rpc, NextEnv = ()> {
32 components: N,
33 rpc_converter: Rpc,
34 gas_cap: GasCap,
35 max_simulate_blocks: u64,
36 compute_state_root_for_eth_simulate: bool,
37 eth_proof_window: u64,
38 fee_history_cache_config: FeeHistoryCacheConfig,
39 proof_permits: usize,
40 eth_state_cache_config: EthStateCacheConfig,
41 eth_cache: Option<EthStateCache<N::Primitives>>,
42 gas_oracle_config: GasPriceOracleConfig,
43 gas_oracle: Option<GasPriceOracle<N::Provider>>,
44 blocking_task_pool: Option<BlockingTaskPool>,
45 task_spawner: Runtime,
46 next_env: NextEnv,
47 max_batch_size: usize,
48 max_blocking_io_requests: usize,
49 pending_block_kind: PendingBlockKind,
50 raw_tx_forwarder: ForwardConfig,
51 sender_recovery_cache: Option<SenderRecoveryCache>,
52 send_raw_transaction_sync_timeout: Duration,
53 evm_memory_limit: u64,
54 force_blob_sidecar_upcasting: bool,
55}
56
57impl<Provider, Pool, Network, EvmConfig, ChainSpec>
58 EthApiBuilder<
59 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
60 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
61 >
62where
63 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
64 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
65{
66 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
68 Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
69 }
70}
71
72impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
73 pub fn apply<F>(self, f: F) -> Self
75 where
76 F: FnOnce(Self) -> Self,
77 {
78 f(self)
79 }
80
81 pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
83 where
84 F: FnOnce(Rpc) -> R,
85 {
86 let Self {
87 components,
88 rpc_converter,
89 gas_cap,
90 max_simulate_blocks,
91 compute_state_root_for_eth_simulate,
92 eth_proof_window,
93 fee_history_cache_config,
94 proof_permits,
95 eth_state_cache_config,
96 eth_cache,
97 gas_oracle_config,
98 gas_oracle,
99 blocking_task_pool,
100 task_spawner,
101 next_env,
102 max_batch_size,
103 max_blocking_io_requests,
104 pending_block_kind,
105 raw_tx_forwarder,
106 sender_recovery_cache,
107 send_raw_transaction_sync_timeout,
108 evm_memory_limit,
109 force_blob_sidecar_upcasting,
110 } = self;
111 EthApiBuilder {
112 components,
113 rpc_converter: f(rpc_converter),
114 gas_cap,
115 max_simulate_blocks,
116 compute_state_root_for_eth_simulate,
117 eth_proof_window,
118 fee_history_cache_config,
119 proof_permits,
120 eth_state_cache_config,
121 eth_cache,
122 gas_oracle_config,
123 gas_oracle,
124 blocking_task_pool,
125 task_spawner,
126 next_env,
127 max_batch_size,
128 max_blocking_io_requests,
129 pending_block_kind,
130 raw_tx_forwarder,
131 sender_recovery_cache,
132 send_raw_transaction_sync_timeout,
133 evm_memory_limit,
134 force_blob_sidecar_upcasting,
135 }
136 }
137}
138
139impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
140where
141 N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
142{
143 pub fn new_with_components(components: N) -> Self {
145 let rpc_converter =
146 RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
147 Self {
148 components,
149 rpc_converter,
150 eth_cache: None,
151 gas_oracle: None,
152 gas_cap: GasCap::default(),
153 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
154 compute_state_root_for_eth_simulate: false,
155 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
156 blocking_task_pool: None,
157 fee_history_cache_config: FeeHistoryCacheConfig::default(),
158 proof_permits: DEFAULT_PROOF_PERMITS,
159 task_spawner: Runtime::test(),
160 gas_oracle_config: Default::default(),
161 eth_state_cache_config: Default::default(),
162 next_env: Default::default(),
163 max_batch_size: 1,
164 max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
165 pending_block_kind: PendingBlockKind::Full,
166 raw_tx_forwarder: ForwardConfig::default(),
167 sender_recovery_cache: None,
168 send_raw_transaction_sync_timeout: Duration::from_secs(30),
169 evm_memory_limit: (1 << 32) - 1,
170 force_blob_sidecar_upcasting: false,
171 }
172 }
173}
174
175impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
176where
177 N: RpcNodeCore,
178{
179 pub fn task_spawner(mut self, spawner: Runtime) -> Self {
181 self.task_spawner = spawner;
182 self
183 }
184
185 pub fn with_rpc_converter<RpcNew>(
187 self,
188 rpc_converter: RpcNew,
189 ) -> EthApiBuilder<N, RpcNew, NextEnv> {
190 let Self {
191 components,
192 rpc_converter: _,
193 gas_cap,
194 max_simulate_blocks,
195 compute_state_root_for_eth_simulate,
196 eth_proof_window,
197 fee_history_cache_config,
198 proof_permits,
199 eth_state_cache_config,
200 eth_cache,
201 gas_oracle,
202 blocking_task_pool,
203 task_spawner,
204 gas_oracle_config,
205 next_env,
206 max_batch_size,
207 max_blocking_io_requests,
208 pending_block_kind,
209 raw_tx_forwarder,
210 sender_recovery_cache,
211 send_raw_transaction_sync_timeout,
212 evm_memory_limit,
213 force_blob_sidecar_upcasting,
214 } = self;
215 EthApiBuilder {
216 components,
217 rpc_converter,
218 gas_cap,
219 max_simulate_blocks,
220 compute_state_root_for_eth_simulate,
221 eth_proof_window,
222 fee_history_cache_config,
223 proof_permits,
224 eth_state_cache_config,
225 eth_cache,
226 gas_oracle,
227 blocking_task_pool,
228 task_spawner,
229 gas_oracle_config,
230 next_env,
231 max_batch_size,
232 max_blocking_io_requests,
233 pending_block_kind,
234 raw_tx_forwarder,
235 sender_recovery_cache,
236 send_raw_transaction_sync_timeout,
237 evm_memory_limit,
238 force_blob_sidecar_upcasting,
239 }
240 }
241
242 pub fn with_pending_env_builder<NextEnvNew>(
244 self,
245 next_env: NextEnvNew,
246 ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
247 let Self {
248 components,
249 rpc_converter,
250 gas_cap,
251 max_simulate_blocks,
252 compute_state_root_for_eth_simulate,
253 eth_proof_window,
254 fee_history_cache_config,
255 proof_permits,
256 eth_state_cache_config,
257 eth_cache,
258 gas_oracle,
259 blocking_task_pool,
260 task_spawner,
261 gas_oracle_config,
262 next_env: _,
263 max_batch_size,
264 max_blocking_io_requests,
265 pending_block_kind,
266 raw_tx_forwarder,
267 sender_recovery_cache,
268 send_raw_transaction_sync_timeout,
269 evm_memory_limit,
270 force_blob_sidecar_upcasting,
271 } = self;
272 EthApiBuilder {
273 components,
274 rpc_converter,
275 gas_cap,
276 max_simulate_blocks,
277 compute_state_root_for_eth_simulate,
278 eth_proof_window,
279 fee_history_cache_config,
280 proof_permits,
281 eth_state_cache_config,
282 eth_cache,
283 gas_oracle,
284 blocking_task_pool,
285 task_spawner,
286 gas_oracle_config,
287 next_env,
288 max_batch_size,
289 max_blocking_io_requests,
290 pending_block_kind,
291 raw_tx_forwarder,
292 sender_recovery_cache,
293 send_raw_transaction_sync_timeout,
294 evm_memory_limit,
295 force_blob_sidecar_upcasting,
296 }
297 }
298
299 pub const fn eth_state_cache_config(
302 mut self,
303 eth_state_cache_config: EthStateCacheConfig,
304 ) -> Self {
305 self.eth_state_cache_config = eth_state_cache_config;
306 self
307 }
308
309 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
311 self.eth_cache = Some(eth_cache);
312 self
313 }
314
315 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
318 self.gas_oracle_config = gas_oracle_config;
319 self
320 }
321
322 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
324 self.gas_oracle = Some(gas_oracle);
325 self
326 }
327
328 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
330 self.gas_cap = gas_cap;
331 self
332 }
333
334 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
336 self.max_simulate_blocks = max_simulate_blocks;
337 self
338 }
339
340 pub const fn compute_state_root_for_eth_simulate(mut self, enabled: bool) -> Self {
342 self.compute_state_root_for_eth_simulate = enabled;
343 self
344 }
345
346 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
348 self.eth_proof_window = eth_proof_window;
349 self
350 }
351
352 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
354 self.blocking_task_pool = Some(blocking_task_pool);
355 self
356 }
357
358 pub const fn fee_history_cache_config(
360 mut self,
361 fee_history_cache_config: FeeHistoryCacheConfig,
362 ) -> Self {
363 self.fee_history_cache_config = fee_history_cache_config;
364 self
365 }
366
367 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
369 self.proof_permits = proof_permits;
370 self
371 }
372
373 pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
375 self.max_batch_size = max_batch_size;
376 self
377 }
378
379 pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
381 self.max_blocking_io_requests = max_blocking_io_requests;
382 self
383 }
384
385 pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
387 self.pending_block_kind = pending_block_kind;
388 self
389 }
390
391 pub fn sender_recovery_cache(mut self, cache: Option<SenderRecoveryCache>) -> Self {
393 self.sender_recovery_cache = cache;
394 self
395 }
396
397 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
399 self.raw_tx_forwarder = tx_forwarder;
400 self
401 }
402
403 pub const fn get_gas_cap(&self) -> &GasCap {
405 &self.gas_cap
406 }
407
408 pub const fn get_max_simulate_blocks(&self) -> u64 {
410 self.max_simulate_blocks
411 }
412
413 pub const fn get_compute_state_root_for_eth_simulate(&self) -> bool {
415 self.compute_state_root_for_eth_simulate
416 }
417
418 pub const fn get_eth_proof_window(&self) -> u64 {
420 self.eth_proof_window
421 }
422
423 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
425 &self.fee_history_cache_config
426 }
427
428 pub const fn get_proof_permits(&self) -> usize {
430 self.proof_permits
431 }
432
433 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
435 &self.eth_state_cache_config
436 }
437
438 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
440 &self.gas_oracle_config
441 }
442
443 pub const fn get_max_batch_size(&self) -> usize {
445 self.max_batch_size
446 }
447
448 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
450 self.pending_block_kind
451 }
452
453 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
455 &self.raw_tx_forwarder
456 }
457
458 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
460 &mut self.fee_history_cache_config
461 }
462
463 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
465 &mut self.eth_state_cache_config
466 }
467
468 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
470 &mut self.gas_oracle_config
471 }
472
473 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
475 &mut self.raw_tx_forwarder
476 }
477
478 pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
480 where
481 F: FnOnce(&mut FeeHistoryCacheConfig),
482 {
483 f(&mut self.fee_history_cache_config);
484 self
485 }
486
487 pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
489 where
490 F: FnOnce(&mut EthStateCacheConfig),
491 {
492 f(&mut self.eth_state_cache_config);
493 self
494 }
495
496 pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
498 where
499 F: FnOnce(&mut GasPriceOracleConfig),
500 {
501 f(&mut self.gas_oracle_config);
502 self
503 }
504
505 pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
507 where
508 F: FnOnce(&mut ForwardConfig),
509 {
510 f(&mut self.raw_tx_forwarder);
511 self
512 }
513
514 pub fn build_inner(self) -> EthApiInner<N, Rpc>
523 where
524 Rpc: RpcConvert,
525 NextEnv: PendingEnvBuilder<N::Evm>,
526 {
527 let Self {
528 components,
529 rpc_converter,
530 eth_state_cache_config,
531 gas_oracle_config,
532 eth_cache,
533 gas_oracle,
534 gas_cap,
535 max_simulate_blocks,
536 compute_state_root_for_eth_simulate,
537 eth_proof_window,
538 blocking_task_pool,
539 fee_history_cache_config,
540 proof_permits,
541 task_spawner,
542 next_env,
543 max_batch_size,
544 max_blocking_io_requests,
545 pending_block_kind,
546 raw_tx_forwarder,
547 sender_recovery_cache,
548 send_raw_transaction_sync_timeout,
549 evm_memory_limit,
550 force_blob_sidecar_upcasting,
551 } = self;
552
553 let provider = components.provider().clone();
554
555 let eth_cache = eth_cache.unwrap_or_else(|| {
556 EthStateCache::spawn_with(
557 provider.clone(),
558 eth_state_cache_config,
559 task_spawner.clone(),
560 )
561 });
562 let gas_oracle = gas_oracle.unwrap_or_else(|| {
563 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
564 });
565 let fee_history_cache =
566 FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
567 let new_canonical_blocks = provider.canonical_state_stream();
568 let fhc = fee_history_cache.clone();
569 let cache = eth_cache.clone();
570 task_spawner.spawn_critical_task(
571 "cache canonical blocks for fee history task",
572 async move {
573 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
574 },
575 );
576
577 let settings = EthApiSettings {
578 sender_recovery_cache,
579 proof_permits,
580 max_batch_size,
581 max_blocking_io_requests,
582 cache_computed_bals: eth_state_cache_config.cache_computed_bals ||
583 eth_state_cache_config.prewarm_bals.is_some(),
584 gas_cap: gas_cap.into(),
585 max_simulate_blocks,
586 compute_state_root_for_eth_simulate,
587 eth_proof_window,
588 pending_block_kind,
589 send_raw_transaction_sync_timeout,
590 evm_memory_limit,
591 force_blob_sidecar_upcasting,
592 };
593
594 EthApiInner::new(
595 components,
596 eth_cache,
597 gas_oracle,
598 settings,
599 blocking_task_pool.unwrap_or_else(|| {
600 BlockingTaskPool::builder()
601 .thread_name(|i| format!("blocking-{i:02}"))
602 .build()
603 .map(BlockingTaskPool::new)
604 .expect("failed to build blocking task pool")
605 }),
606 fee_history_cache,
607 task_spawner,
608 rpc_converter,
609 next_env,
610 raw_tx_forwarder.forwarder_client(),
611 )
612 }
613
614 pub fn build(self) -> EthApi<N, Rpc>
623 where
624 Rpc: RpcConvert,
625 NextEnv: PendingEnvBuilder<N::Evm>,
626 {
627 EthApi { inner: Arc::new(self.build_inner()) }
628 }
629
630 pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
632 self.send_raw_transaction_sync_timeout = timeout;
633 self
634 }
635
636 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
638 self.evm_memory_limit = memory_limit;
639 self
640 }
641
642 pub const fn force_blob_sidecar_upcasting(mut self, force: bool) -> Self {
644 self.force_blob_sidecar_upcasting = force;
645 self
646 }
647}