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, Runtime};
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 compute_state_root_for_eth_simulate: bool,
35 eth_proof_window: u64,
36 fee_history_cache_config: FeeHistoryCacheConfig,
37 proof_permits: usize,
38 eth_state_cache_config: EthStateCacheConfig,
39 eth_cache: Option<EthStateCache<N::Primitives>>,
40 gas_oracle_config: GasPriceOracleConfig,
41 gas_oracle: Option<GasPriceOracle<N::Provider>>,
42 blocking_task_pool: Option<BlockingTaskPool>,
43 task_spawner: Runtime,
44 next_env: NextEnv,
45 max_batch_size: usize,
46 max_blocking_io_requests: usize,
47 pending_block_kind: PendingBlockKind,
48 raw_tx_forwarder: ForwardConfig,
49 send_raw_transaction_sync_timeout: Duration,
50 evm_memory_limit: u64,
51 force_blob_sidecar_upcasting: bool,
52}
53
54impl<Provider, Pool, Network, EvmConfig, ChainSpec>
55 EthApiBuilder<
56 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
57 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
58 >
59where
60 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
61 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
62{
63 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
65 Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
66 }
67}
68
69impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
70 pub fn apply<F>(self, f: F) -> Self
72 where
73 F: FnOnce(Self) -> Self,
74 {
75 f(self)
76 }
77
78 pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
80 where
81 F: FnOnce(Rpc) -> R,
82 {
83 let Self {
84 components,
85 rpc_converter,
86 gas_cap,
87 max_simulate_blocks,
88 compute_state_root_for_eth_simulate,
89 eth_proof_window,
90 fee_history_cache_config,
91 proof_permits,
92 eth_state_cache_config,
93 eth_cache,
94 gas_oracle_config,
95 gas_oracle,
96 blocking_task_pool,
97 task_spawner,
98 next_env,
99 max_batch_size,
100 max_blocking_io_requests,
101 pending_block_kind,
102 raw_tx_forwarder,
103 send_raw_transaction_sync_timeout,
104 evm_memory_limit,
105 force_blob_sidecar_upcasting,
106 } = self;
107 EthApiBuilder {
108 components,
109 rpc_converter: f(rpc_converter),
110 gas_cap,
111 max_simulate_blocks,
112 compute_state_root_for_eth_simulate,
113 eth_proof_window,
114 fee_history_cache_config,
115 proof_permits,
116 eth_state_cache_config,
117 eth_cache,
118 gas_oracle_config,
119 gas_oracle,
120 blocking_task_pool,
121 task_spawner,
122 next_env,
123 max_batch_size,
124 max_blocking_io_requests,
125 pending_block_kind,
126 raw_tx_forwarder,
127 send_raw_transaction_sync_timeout,
128 evm_memory_limit,
129 force_blob_sidecar_upcasting,
130 }
131 }
132}
133
134impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
135where
136 N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
137{
138 pub fn new_with_components(components: N) -> Self {
140 let rpc_converter =
141 RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
142 Self {
143 components,
144 rpc_converter,
145 eth_cache: None,
146 gas_oracle: None,
147 gas_cap: GasCap::default(),
148 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
149 compute_state_root_for_eth_simulate: false,
150 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
151 blocking_task_pool: None,
152 fee_history_cache_config: FeeHistoryCacheConfig::default(),
153 proof_permits: DEFAULT_PROOF_PERMITS,
154 task_spawner: Runtime::test(),
155 gas_oracle_config: Default::default(),
156 eth_state_cache_config: Default::default(),
157 next_env: Default::default(),
158 max_batch_size: 1,
159 max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
160 pending_block_kind: PendingBlockKind::Full,
161 raw_tx_forwarder: ForwardConfig::default(),
162 send_raw_transaction_sync_timeout: Duration::from_secs(30),
163 evm_memory_limit: (1 << 32) - 1,
164 force_blob_sidecar_upcasting: false,
165 }
166 }
167}
168
169impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
170where
171 N: RpcNodeCore,
172{
173 pub fn task_spawner(mut self, spawner: Runtime) -> Self {
175 self.task_spawner = spawner;
176 self
177 }
178
179 pub fn with_rpc_converter<RpcNew>(
181 self,
182 rpc_converter: RpcNew,
183 ) -> EthApiBuilder<N, RpcNew, NextEnv> {
184 let Self {
185 components,
186 rpc_converter: _,
187 gas_cap,
188 max_simulate_blocks,
189 compute_state_root_for_eth_simulate,
190 eth_proof_window,
191 fee_history_cache_config,
192 proof_permits,
193 eth_state_cache_config,
194 eth_cache,
195 gas_oracle,
196 blocking_task_pool,
197 task_spawner,
198 gas_oracle_config,
199 next_env,
200 max_batch_size,
201 max_blocking_io_requests,
202 pending_block_kind,
203 raw_tx_forwarder,
204 send_raw_transaction_sync_timeout,
205 evm_memory_limit,
206 force_blob_sidecar_upcasting,
207 } = self;
208 EthApiBuilder {
209 components,
210 rpc_converter,
211 gas_cap,
212 max_simulate_blocks,
213 compute_state_root_for_eth_simulate,
214 eth_proof_window,
215 fee_history_cache_config,
216 proof_permits,
217 eth_state_cache_config,
218 eth_cache,
219 gas_oracle,
220 blocking_task_pool,
221 task_spawner,
222 gas_oracle_config,
223 next_env,
224 max_batch_size,
225 max_blocking_io_requests,
226 pending_block_kind,
227 raw_tx_forwarder,
228 send_raw_transaction_sync_timeout,
229 evm_memory_limit,
230 force_blob_sidecar_upcasting,
231 }
232 }
233
234 pub fn with_pending_env_builder<NextEnvNew>(
236 self,
237 next_env: NextEnvNew,
238 ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
239 let Self {
240 components,
241 rpc_converter,
242 gas_cap,
243 max_simulate_blocks,
244 compute_state_root_for_eth_simulate,
245 eth_proof_window,
246 fee_history_cache_config,
247 proof_permits,
248 eth_state_cache_config,
249 eth_cache,
250 gas_oracle,
251 blocking_task_pool,
252 task_spawner,
253 gas_oracle_config,
254 next_env: _,
255 max_batch_size,
256 max_blocking_io_requests,
257 pending_block_kind,
258 raw_tx_forwarder,
259 send_raw_transaction_sync_timeout,
260 evm_memory_limit,
261 force_blob_sidecar_upcasting,
262 } = self;
263 EthApiBuilder {
264 components,
265 rpc_converter,
266 gas_cap,
267 max_simulate_blocks,
268 compute_state_root_for_eth_simulate,
269 eth_proof_window,
270 fee_history_cache_config,
271 proof_permits,
272 eth_state_cache_config,
273 eth_cache,
274 gas_oracle,
275 blocking_task_pool,
276 task_spawner,
277 gas_oracle_config,
278 next_env,
279 max_batch_size,
280 max_blocking_io_requests,
281 pending_block_kind,
282 raw_tx_forwarder,
283 send_raw_transaction_sync_timeout,
284 evm_memory_limit,
285 force_blob_sidecar_upcasting,
286 }
287 }
288
289 pub const fn eth_state_cache_config(
292 mut self,
293 eth_state_cache_config: EthStateCacheConfig,
294 ) -> Self {
295 self.eth_state_cache_config = eth_state_cache_config;
296 self
297 }
298
299 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
301 self.eth_cache = Some(eth_cache);
302 self
303 }
304
305 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
308 self.gas_oracle_config = gas_oracle_config;
309 self
310 }
311
312 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
314 self.gas_oracle = Some(gas_oracle);
315 self
316 }
317
318 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
320 self.gas_cap = gas_cap;
321 self
322 }
323
324 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
326 self.max_simulate_blocks = max_simulate_blocks;
327 self
328 }
329
330 pub const fn compute_state_root_for_eth_simulate(mut self, enabled: bool) -> Self {
332 self.compute_state_root_for_eth_simulate = enabled;
333 self
334 }
335
336 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
338 self.eth_proof_window = eth_proof_window;
339 self
340 }
341
342 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
344 self.blocking_task_pool = Some(blocking_task_pool);
345 self
346 }
347
348 pub const fn fee_history_cache_config(
350 mut self,
351 fee_history_cache_config: FeeHistoryCacheConfig,
352 ) -> Self {
353 self.fee_history_cache_config = fee_history_cache_config;
354 self
355 }
356
357 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
359 self.proof_permits = proof_permits;
360 self
361 }
362
363 pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
365 self.max_batch_size = max_batch_size;
366 self
367 }
368
369 pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
371 self.max_blocking_io_requests = max_blocking_io_requests;
372 self
373 }
374
375 pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
377 self.pending_block_kind = pending_block_kind;
378 self
379 }
380
381 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
383 self.raw_tx_forwarder = tx_forwarder;
384 self
385 }
386
387 pub const fn get_gas_cap(&self) -> &GasCap {
389 &self.gas_cap
390 }
391
392 pub const fn get_max_simulate_blocks(&self) -> u64 {
394 self.max_simulate_blocks
395 }
396
397 pub const fn get_compute_state_root_for_eth_simulate(&self) -> bool {
399 self.compute_state_root_for_eth_simulate
400 }
401
402 pub const fn get_eth_proof_window(&self) -> u64 {
404 self.eth_proof_window
405 }
406
407 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
409 &self.fee_history_cache_config
410 }
411
412 pub const fn get_proof_permits(&self) -> usize {
414 self.proof_permits
415 }
416
417 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
419 &self.eth_state_cache_config
420 }
421
422 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
424 &self.gas_oracle_config
425 }
426
427 pub const fn get_max_batch_size(&self) -> usize {
429 self.max_batch_size
430 }
431
432 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
434 self.pending_block_kind
435 }
436
437 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
439 &self.raw_tx_forwarder
440 }
441
442 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
444 &mut self.fee_history_cache_config
445 }
446
447 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
449 &mut self.eth_state_cache_config
450 }
451
452 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
454 &mut self.gas_oracle_config
455 }
456
457 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
459 &mut self.raw_tx_forwarder
460 }
461
462 pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
464 where
465 F: FnOnce(&mut FeeHistoryCacheConfig),
466 {
467 f(&mut self.fee_history_cache_config);
468 self
469 }
470
471 pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
473 where
474 F: FnOnce(&mut EthStateCacheConfig),
475 {
476 f(&mut self.eth_state_cache_config);
477 self
478 }
479
480 pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
482 where
483 F: FnOnce(&mut GasPriceOracleConfig),
484 {
485 f(&mut self.gas_oracle_config);
486 self
487 }
488
489 pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
491 where
492 F: FnOnce(&mut ForwardConfig),
493 {
494 f(&mut self.raw_tx_forwarder);
495 self
496 }
497
498 pub fn build_inner(self) -> EthApiInner<N, Rpc>
507 where
508 Rpc: RpcConvert,
509 NextEnv: PendingEnvBuilder<N::Evm>,
510 {
511 let Self {
512 components,
513 rpc_converter,
514 eth_state_cache_config,
515 gas_oracle_config,
516 eth_cache,
517 gas_oracle,
518 gas_cap,
519 max_simulate_blocks,
520 compute_state_root_for_eth_simulate,
521 eth_proof_window,
522 blocking_task_pool,
523 fee_history_cache_config,
524 proof_permits,
525 task_spawner,
526 next_env,
527 max_batch_size,
528 max_blocking_io_requests,
529 pending_block_kind,
530 raw_tx_forwarder,
531 send_raw_transaction_sync_timeout,
532 evm_memory_limit,
533 force_blob_sidecar_upcasting,
534 } = self;
535
536 let provider = components.provider().clone();
537
538 let eth_cache = eth_cache.unwrap_or_else(|| {
539 EthStateCache::spawn_with(
540 provider.clone(),
541 eth_state_cache_config,
542 task_spawner.clone(),
543 )
544 });
545 let gas_oracle = gas_oracle.unwrap_or_else(|| {
546 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
547 });
548 let fee_history_cache =
549 FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
550 let new_canonical_blocks = provider.canonical_state_stream();
551 let fhc = fee_history_cache.clone();
552 let cache = eth_cache.clone();
553 task_spawner.spawn_critical_task(
554 "cache canonical blocks for fee history task",
555 async move {
556 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
557 },
558 );
559
560 EthApiInner::new(
561 components,
562 eth_cache,
563 gas_oracle,
564 gas_cap,
565 max_simulate_blocks,
566 compute_state_root_for_eth_simulate,
567 eth_proof_window,
568 blocking_task_pool.unwrap_or_else(|| {
569 BlockingTaskPool::builder()
570 .thread_name(|i| format!("blocking-{i:02}"))
571 .build()
572 .map(BlockingTaskPool::new)
573 .expect("failed to build blocking task pool")
574 }),
575 fee_history_cache,
576 task_spawner,
577 proof_permits,
578 rpc_converter,
579 next_env,
580 max_batch_size,
581 max_blocking_io_requests,
582 pending_block_kind,
583 raw_tx_forwarder.forwarder_client(),
584 send_raw_transaction_sync_timeout,
585 evm_memory_limit,
586 force_blob_sidecar_upcasting,
587 )
588 }
589
590 pub fn build(self) -> EthApi<N, Rpc>
599 where
600 Rpc: RpcConvert,
601 NextEnv: PendingEnvBuilder<N::Evm>,
602 {
603 EthApi { inner: Arc::new(self.build_inner()) }
604 }
605
606 pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
608 self.send_raw_transaction_sync_timeout = timeout;
609 self
610 }
611
612 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
614 self.evm_memory_limit = memory_limit;
615 self
616 }
617
618 pub const fn force_blob_sidecar_upcasting(mut self, force: bool) -> Self {
620 self.force_blob_sidecar_upcasting = force;
621 self
622 }
623}