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: Option<Runtime>,
47 next_env: NextEnv,
48 max_batch_size: usize,
49 max_blocking_io_requests: usize,
50 pending_block_kind: PendingBlockKind,
51 raw_tx_forwarder: ForwardConfig,
52 sender_recovery_cache: Option<SenderRecoveryCache>,
53 send_raw_transaction_sync_timeout: Duration,
54 evm_memory_limit: u64,
55 force_blob_sidecar_upcasting: bool,
56}
57
58impl<Provider, Pool, Network, EvmConfig, ChainSpec>
59 EthApiBuilder<
60 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
61 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
62 >
63where
64 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
65 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
66{
67 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
69 Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
70 }
71}
72
73impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
74 pub fn apply<F>(self, f: F) -> Self
76 where
77 F: FnOnce(Self) -> Self,
78 {
79 f(self)
80 }
81
82 pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
84 where
85 F: FnOnce(Rpc) -> R,
86 {
87 let Self {
88 components,
89 rpc_converter,
90 gas_cap,
91 max_simulate_blocks,
92 compute_state_root_for_eth_simulate,
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 max_blocking_io_requests,
105 pending_block_kind,
106 raw_tx_forwarder,
107 sender_recovery_cache,
108 send_raw_transaction_sync_timeout,
109 evm_memory_limit,
110 force_blob_sidecar_upcasting,
111 } = self;
112 EthApiBuilder {
113 components,
114 rpc_converter: f(rpc_converter),
115 gas_cap,
116 max_simulate_blocks,
117 compute_state_root_for_eth_simulate,
118 eth_proof_window,
119 fee_history_cache_config,
120 proof_permits,
121 eth_state_cache_config,
122 eth_cache,
123 gas_oracle_config,
124 gas_oracle,
125 blocking_task_pool,
126 task_spawner,
127 next_env,
128 max_batch_size,
129 max_blocking_io_requests,
130 pending_block_kind,
131 raw_tx_forwarder,
132 sender_recovery_cache,
133 send_raw_transaction_sync_timeout,
134 evm_memory_limit,
135 force_blob_sidecar_upcasting,
136 }
137 }
138}
139
140impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
141where
142 N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
143{
144 pub fn new_with_components(components: N) -> Self {
146 let rpc_converter =
147 RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
148 Self {
149 components,
150 rpc_converter,
151 eth_cache: None,
152 gas_oracle: None,
153 gas_cap: GasCap::default(),
154 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
155 compute_state_root_for_eth_simulate: false,
156 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
157 blocking_task_pool: None,
158 fee_history_cache_config: FeeHistoryCacheConfig::default(),
159 proof_permits: DEFAULT_PROOF_PERMITS,
160 task_spawner: None,
161 gas_oracle_config: Default::default(),
162 eth_state_cache_config: Default::default(),
163 next_env: Default::default(),
164 max_batch_size: 1,
165 max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
166 pending_block_kind: PendingBlockKind::Full,
167 raw_tx_forwarder: ForwardConfig::default(),
168 sender_recovery_cache: None,
169 send_raw_transaction_sync_timeout: Duration::from_secs(30),
170 evm_memory_limit: (1 << 32) - 1,
171 force_blob_sidecar_upcasting: false,
172 }
173 }
174}
175
176impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
177where
178 N: RpcNodeCore,
179{
180 pub fn task_spawner(mut self, spawner: Runtime) -> Self {
182 self.task_spawner = Some(spawner);
183 self
184 }
185
186 pub fn with_rpc_converter<RpcNew>(
188 self,
189 rpc_converter: RpcNew,
190 ) -> EthApiBuilder<N, RpcNew, NextEnv> {
191 let Self {
192 components,
193 rpc_converter: _,
194 gas_cap,
195 max_simulate_blocks,
196 compute_state_root_for_eth_simulate,
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 max_blocking_io_requests,
209 pending_block_kind,
210 raw_tx_forwarder,
211 sender_recovery_cache,
212 send_raw_transaction_sync_timeout,
213 evm_memory_limit,
214 force_blob_sidecar_upcasting,
215 } = self;
216 EthApiBuilder {
217 components,
218 rpc_converter,
219 gas_cap,
220 max_simulate_blocks,
221 compute_state_root_for_eth_simulate,
222 eth_proof_window,
223 fee_history_cache_config,
224 proof_permits,
225 eth_state_cache_config,
226 eth_cache,
227 gas_oracle,
228 blocking_task_pool,
229 task_spawner,
230 gas_oracle_config,
231 next_env,
232 max_batch_size,
233 max_blocking_io_requests,
234 pending_block_kind,
235 raw_tx_forwarder,
236 sender_recovery_cache,
237 send_raw_transaction_sync_timeout,
238 evm_memory_limit,
239 force_blob_sidecar_upcasting,
240 }
241 }
242
243 pub fn with_pending_env_builder<NextEnvNew>(
245 self,
246 next_env: NextEnvNew,
247 ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
248 let Self {
249 components,
250 rpc_converter,
251 gas_cap,
252 max_simulate_blocks,
253 compute_state_root_for_eth_simulate,
254 eth_proof_window,
255 fee_history_cache_config,
256 proof_permits,
257 eth_state_cache_config,
258 eth_cache,
259 gas_oracle,
260 blocking_task_pool,
261 task_spawner,
262 gas_oracle_config,
263 next_env: _,
264 max_batch_size,
265 max_blocking_io_requests,
266 pending_block_kind,
267 raw_tx_forwarder,
268 sender_recovery_cache,
269 send_raw_transaction_sync_timeout,
270 evm_memory_limit,
271 force_blob_sidecar_upcasting,
272 } = self;
273 EthApiBuilder {
274 components,
275 rpc_converter,
276 gas_cap,
277 max_simulate_blocks,
278 compute_state_root_for_eth_simulate,
279 eth_proof_window,
280 fee_history_cache_config,
281 proof_permits,
282 eth_state_cache_config,
283 eth_cache,
284 gas_oracle,
285 blocking_task_pool,
286 task_spawner,
287 gas_oracle_config,
288 next_env,
289 max_batch_size,
290 max_blocking_io_requests,
291 pending_block_kind,
292 raw_tx_forwarder,
293 sender_recovery_cache,
294 send_raw_transaction_sync_timeout,
295 evm_memory_limit,
296 force_blob_sidecar_upcasting,
297 }
298 }
299
300 pub const fn eth_state_cache_config(
303 mut self,
304 eth_state_cache_config: EthStateCacheConfig,
305 ) -> Self {
306 self.eth_state_cache_config = eth_state_cache_config;
307 self
308 }
309
310 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
312 self.eth_cache = Some(eth_cache);
313 self
314 }
315
316 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
319 self.gas_oracle_config = gas_oracle_config;
320 self
321 }
322
323 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
325 self.gas_oracle = Some(gas_oracle);
326 self
327 }
328
329 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
331 self.gas_cap = gas_cap;
332 self
333 }
334
335 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
337 self.max_simulate_blocks = max_simulate_blocks;
338 self
339 }
340
341 pub const fn compute_state_root_for_eth_simulate(mut self, enabled: bool) -> Self {
343 self.compute_state_root_for_eth_simulate = enabled;
344 self
345 }
346
347 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
349 self.eth_proof_window = eth_proof_window;
350 self
351 }
352
353 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
355 self.blocking_task_pool = Some(blocking_task_pool);
356 self
357 }
358
359 pub const fn fee_history_cache_config(
361 mut self,
362 fee_history_cache_config: FeeHistoryCacheConfig,
363 ) -> Self {
364 self.fee_history_cache_config = fee_history_cache_config;
365 self
366 }
367
368 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
370 self.proof_permits = proof_permits;
371 self
372 }
373
374 pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
376 self.max_batch_size = max_batch_size;
377 self
378 }
379
380 pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
382 self.max_blocking_io_requests = max_blocking_io_requests;
383 self
384 }
385
386 pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
388 self.pending_block_kind = pending_block_kind;
389 self
390 }
391
392 pub fn sender_recovery_cache(mut self, cache: Option<SenderRecoveryCache>) -> Self {
394 self.sender_recovery_cache = cache;
395 self
396 }
397
398 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
400 self.raw_tx_forwarder = tx_forwarder;
401 self
402 }
403
404 pub const fn get_gas_cap(&self) -> &GasCap {
406 &self.gas_cap
407 }
408
409 pub const fn get_max_simulate_blocks(&self) -> u64 {
411 self.max_simulate_blocks
412 }
413
414 pub const fn get_compute_state_root_for_eth_simulate(&self) -> bool {
416 self.compute_state_root_for_eth_simulate
417 }
418
419 pub const fn get_eth_proof_window(&self) -> u64 {
421 self.eth_proof_window
422 }
423
424 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
426 &self.fee_history_cache_config
427 }
428
429 pub const fn get_proof_permits(&self) -> usize {
431 self.proof_permits
432 }
433
434 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
436 &self.eth_state_cache_config
437 }
438
439 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
441 &self.gas_oracle_config
442 }
443
444 pub const fn get_max_batch_size(&self) -> usize {
446 self.max_batch_size
447 }
448
449 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
451 self.pending_block_kind
452 }
453
454 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
456 &self.raw_tx_forwarder
457 }
458
459 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
461 &mut self.fee_history_cache_config
462 }
463
464 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
466 &mut self.eth_state_cache_config
467 }
468
469 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
471 &mut self.gas_oracle_config
472 }
473
474 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
476 &mut self.raw_tx_forwarder
477 }
478
479 pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
481 where
482 F: FnOnce(&mut FeeHistoryCacheConfig),
483 {
484 f(&mut self.fee_history_cache_config);
485 self
486 }
487
488 pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
490 where
491 F: FnOnce(&mut EthStateCacheConfig),
492 {
493 f(&mut self.eth_state_cache_config);
494 self
495 }
496
497 pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
499 where
500 F: FnOnce(&mut GasPriceOracleConfig),
501 {
502 f(&mut self.gas_oracle_config);
503 self
504 }
505
506 pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
508 where
509 F: FnOnce(&mut ForwardConfig),
510 {
511 f(&mut self.raw_tx_forwarder);
512 self
513 }
514
515 pub fn build_inner(self) -> EthApiInner<N, Rpc>
524 where
525 Rpc: RpcConvert,
526 NextEnv: PendingEnvBuilder<N::Evm>,
527 {
528 let Self {
529 components,
530 rpc_converter,
531 eth_state_cache_config,
532 gas_oracle_config,
533 eth_cache,
534 gas_oracle,
535 gas_cap,
536 max_simulate_blocks,
537 compute_state_root_for_eth_simulate,
538 eth_proof_window,
539 blocking_task_pool,
540 fee_history_cache_config,
541 proof_permits,
542 task_spawner,
543 next_env,
544 max_batch_size,
545 max_blocking_io_requests,
546 pending_block_kind,
547 raw_tx_forwarder,
548 sender_recovery_cache,
549 send_raw_transaction_sync_timeout,
550 evm_memory_limit,
551 force_blob_sidecar_upcasting,
552 } = self;
553
554 let provider = components.provider().clone();
555 let task_spawner = task_spawner.unwrap_or_else(Runtime::test);
556
557 let eth_cache = eth_cache.unwrap_or_else(|| {
558 EthStateCache::spawn_with(
559 provider.clone(),
560 eth_state_cache_config,
561 task_spawner.clone(),
562 )
563 });
564 let gas_oracle = gas_oracle.unwrap_or_else(|| {
565 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
566 });
567 let fee_history_cache =
568 FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
569 let new_canonical_blocks = provider.canonical_state_stream();
570 let fhc = fee_history_cache.clone();
571 let cache = eth_cache.clone();
572 task_spawner.spawn_critical_task(
573 "cache canonical blocks for fee history task",
574 async move {
575 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
576 },
577 );
578
579 let settings = EthApiSettings {
580 sender_recovery_cache,
581 proof_permits,
582 max_batch_size,
583 max_blocking_io_requests,
584 cache_computed_bals: eth_state_cache_config.cache_computed_bals ||
585 eth_state_cache_config.prewarm_bals.is_some(),
586 gas_cap: gas_cap.into(),
587 max_simulate_blocks,
588 compute_state_root_for_eth_simulate,
589 eth_proof_window,
590 pending_block_kind,
591 send_raw_transaction_sync_timeout,
592 evm_memory_limit,
593 force_blob_sidecar_upcasting,
594 };
595
596 EthApiInner::new(
597 components,
598 eth_cache,
599 gas_oracle,
600 settings,
601 blocking_task_pool.unwrap_or_else(|| {
602 BlockingTaskPool::builder()
603 .thread_name(|i| format!("blocking-{i:02}"))
604 .build()
605 .map(BlockingTaskPool::new)
606 .expect("failed to build blocking task pool")
607 }),
608 fee_history_cache,
609 task_spawner,
610 rpc_converter,
611 next_env,
612 raw_tx_forwarder.forwarder_client(),
613 )
614 }
615
616 pub fn build(self) -> EthApi<N, Rpc>
625 where
626 Rpc: RpcConvert,
627 NextEnv: PendingEnvBuilder<N::Evm>,
628 {
629 EthApi { inner: Arc::new(self.build_inner()) }
630 }
631
632 pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
634 self.send_raw_transaction_sync_timeout = timeout;
635 self
636 }
637
638 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
640 self.evm_memory_limit = memory_limit;
641 self
642 }
643
644 pub const fn force_blob_sidecar_upcasting(mut self, force: bool) -> Self {
646 self.force_blob_sidecar_upcasting = force;
647 self
648 }
649}