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}
51
52impl<Provider, Pool, Network, EvmConfig, ChainSpec>
53 EthApiBuilder<
54 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
55 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
56 >
57where
58 RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
59 RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
60{
61 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self {
63 Self::new_with_components(RpcNodeCoreAdapter::new(provider, pool, network, evm_config))
64 }
65}
66
67impl<N: RpcNodeCore, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv> {
68 pub fn apply<F>(self, f: F) -> Self
70 where
71 F: FnOnce(Self) -> Self,
72 {
73 f(self)
74 }
75
76 pub fn map_converter<F, R>(self, f: F) -> EthApiBuilder<N, R, NextEnv>
78 where
79 F: FnOnce(Rpc) -> R,
80 {
81 let Self {
82 components,
83 rpc_converter,
84 gas_cap,
85 max_simulate_blocks,
86 eth_proof_window,
87 fee_history_cache_config,
88 proof_permits,
89 eth_state_cache_config,
90 eth_cache,
91 gas_oracle_config,
92 gas_oracle,
93 blocking_task_pool,
94 task_spawner,
95 next_env,
96 max_batch_size,
97 max_blocking_io_requests,
98 pending_block_kind,
99 raw_tx_forwarder,
100 send_raw_transaction_sync_timeout,
101 evm_memory_limit,
102 } = self;
103 EthApiBuilder {
104 components,
105 rpc_converter: f(rpc_converter),
106 gas_cap,
107 max_simulate_blocks,
108 eth_proof_window,
109 fee_history_cache_config,
110 proof_permits,
111 eth_state_cache_config,
112 eth_cache,
113 gas_oracle_config,
114 gas_oracle,
115 blocking_task_pool,
116 task_spawner,
117 next_env,
118 max_batch_size,
119 max_blocking_io_requests,
120 pending_block_kind,
121 raw_tx_forwarder,
122 send_raw_transaction_sync_timeout,
123 evm_memory_limit,
124 }
125 }
126}
127
128impl<N, ChainSpec> EthApiBuilder<N, RpcConverter<Ethereum, N::Evm, EthReceiptConverter<ChainSpec>>>
129where
130 N: RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>>,
131{
132 pub fn new_with_components(components: N) -> Self {
134 let rpc_converter =
135 RpcConverter::new(EthReceiptConverter::new(components.provider().chain_spec()));
136 Self {
137 components,
138 rpc_converter,
139 eth_cache: None,
140 gas_oracle: None,
141 gas_cap: GasCap::default(),
142 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
143 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
144 blocking_task_pool: None,
145 fee_history_cache_config: FeeHistoryCacheConfig::default(),
146 proof_permits: DEFAULT_PROOF_PERMITS,
147 task_spawner: TokioTaskExecutor::default().boxed(),
148 gas_oracle_config: Default::default(),
149 eth_state_cache_config: Default::default(),
150 next_env: Default::default(),
151 max_batch_size: 1,
152 max_blocking_io_requests: DEFAULT_MAX_BLOCKING_IO_REQUEST,
153 pending_block_kind: PendingBlockKind::Full,
154 raw_tx_forwarder: ForwardConfig::default(),
155 send_raw_transaction_sync_timeout: Duration::from_secs(30),
156 evm_memory_limit: (1 << 32) - 1,
157 }
158 }
159}
160
161impl<N, Rpc, NextEnv> EthApiBuilder<N, Rpc, NextEnv>
162where
163 N: RpcNodeCore,
164{
165 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
167 self.task_spawner = Box::new(spawner);
168 self
169 }
170
171 pub fn with_rpc_converter<RpcNew>(
173 self,
174 rpc_converter: RpcNew,
175 ) -> EthApiBuilder<N, RpcNew, NextEnv> {
176 let Self {
177 components,
178 rpc_converter: _,
179 gas_cap,
180 max_simulate_blocks,
181 eth_proof_window,
182 fee_history_cache_config,
183 proof_permits,
184 eth_state_cache_config,
185 eth_cache,
186 gas_oracle,
187 blocking_task_pool,
188 task_spawner,
189 gas_oracle_config,
190 next_env,
191 max_batch_size,
192 max_blocking_io_requests,
193 pending_block_kind,
194 raw_tx_forwarder,
195 send_raw_transaction_sync_timeout,
196 evm_memory_limit,
197 } = self;
198 EthApiBuilder {
199 components,
200 rpc_converter,
201 gas_cap,
202 max_simulate_blocks,
203 eth_proof_window,
204 fee_history_cache_config,
205 proof_permits,
206 eth_state_cache_config,
207 eth_cache,
208 gas_oracle,
209 blocking_task_pool,
210 task_spawner,
211 gas_oracle_config,
212 next_env,
213 max_batch_size,
214 max_blocking_io_requests,
215 pending_block_kind,
216 raw_tx_forwarder,
217 send_raw_transaction_sync_timeout,
218 evm_memory_limit,
219 }
220 }
221
222 pub fn with_pending_env_builder<NextEnvNew>(
224 self,
225 next_env: NextEnvNew,
226 ) -> EthApiBuilder<N, Rpc, NextEnvNew> {
227 let Self {
228 components,
229 rpc_converter,
230 gas_cap,
231 max_simulate_blocks,
232 eth_proof_window,
233 fee_history_cache_config,
234 proof_permits,
235 eth_state_cache_config,
236 eth_cache,
237 gas_oracle,
238 blocking_task_pool,
239 task_spawner,
240 gas_oracle_config,
241 next_env: _,
242 max_batch_size,
243 max_blocking_io_requests,
244 pending_block_kind,
245 raw_tx_forwarder,
246 send_raw_transaction_sync_timeout,
247 evm_memory_limit,
248 } = self;
249 EthApiBuilder {
250 components,
251 rpc_converter,
252 gas_cap,
253 max_simulate_blocks,
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 send_raw_transaction_sync_timeout,
269 evm_memory_limit,
270 }
271 }
272
273 pub const fn eth_state_cache_config(
276 mut self,
277 eth_state_cache_config: EthStateCacheConfig,
278 ) -> Self {
279 self.eth_state_cache_config = eth_state_cache_config;
280 self
281 }
282
283 pub fn eth_cache(mut self, eth_cache: EthStateCache<N::Primitives>) -> Self {
285 self.eth_cache = Some(eth_cache);
286 self
287 }
288
289 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
292 self.gas_oracle_config = gas_oracle_config;
293 self
294 }
295
296 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<N::Provider>) -> Self {
298 self.gas_oracle = Some(gas_oracle);
299 self
300 }
301
302 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
304 self.gas_cap = gas_cap;
305 self
306 }
307
308 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
310 self.max_simulate_blocks = max_simulate_blocks;
311 self
312 }
313
314 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
316 self.eth_proof_window = eth_proof_window;
317 self
318 }
319
320 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
322 self.blocking_task_pool = Some(blocking_task_pool);
323 self
324 }
325
326 pub const fn fee_history_cache_config(
328 mut self,
329 fee_history_cache_config: FeeHistoryCacheConfig,
330 ) -> Self {
331 self.fee_history_cache_config = fee_history_cache_config;
332 self
333 }
334
335 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
337 self.proof_permits = proof_permits;
338 self
339 }
340
341 pub const fn max_batch_size(mut self, max_batch_size: usize) -> Self {
343 self.max_batch_size = max_batch_size;
344 self
345 }
346
347 pub const fn max_blocking_io_requests(mut self, max_blocking_io_requests: usize) -> Self {
349 self.max_blocking_io_requests = max_blocking_io_requests;
350 self
351 }
352
353 pub const fn pending_block_kind(mut self, pending_block_kind: PendingBlockKind) -> Self {
355 self.pending_block_kind = pending_block_kind;
356 self
357 }
358
359 pub fn raw_tx_forwarder(mut self, tx_forwarder: ForwardConfig) -> Self {
361 self.raw_tx_forwarder = tx_forwarder;
362 self
363 }
364
365 pub const fn get_gas_cap(&self) -> &GasCap {
367 &self.gas_cap
368 }
369
370 pub const fn get_max_simulate_blocks(&self) -> u64 {
372 self.max_simulate_blocks
373 }
374
375 pub const fn get_eth_proof_window(&self) -> u64 {
377 self.eth_proof_window
378 }
379
380 pub const fn get_fee_history_cache_config(&self) -> &FeeHistoryCacheConfig {
382 &self.fee_history_cache_config
383 }
384
385 pub const fn get_proof_permits(&self) -> usize {
387 self.proof_permits
388 }
389
390 pub const fn get_eth_state_cache_config(&self) -> &EthStateCacheConfig {
392 &self.eth_state_cache_config
393 }
394
395 pub const fn get_gas_oracle_config(&self) -> &GasPriceOracleConfig {
397 &self.gas_oracle_config
398 }
399
400 pub const fn get_max_batch_size(&self) -> usize {
402 self.max_batch_size
403 }
404
405 pub const fn get_pending_block_kind(&self) -> PendingBlockKind {
407 self.pending_block_kind
408 }
409
410 pub const fn get_raw_tx_forwarder(&self) -> &ForwardConfig {
412 &self.raw_tx_forwarder
413 }
414
415 pub const fn fee_history_cache_config_mut(&mut self) -> &mut FeeHistoryCacheConfig {
417 &mut self.fee_history_cache_config
418 }
419
420 pub const fn eth_state_cache_config_mut(&mut self) -> &mut EthStateCacheConfig {
422 &mut self.eth_state_cache_config
423 }
424
425 pub const fn gas_oracle_config_mut(&mut self) -> &mut GasPriceOracleConfig {
427 &mut self.gas_oracle_config
428 }
429
430 pub const fn raw_tx_forwarder_mut(&mut self) -> &mut ForwardConfig {
432 &mut self.raw_tx_forwarder
433 }
434
435 pub fn modify_fee_history_cache_config<F>(mut self, f: F) -> Self
437 where
438 F: FnOnce(&mut FeeHistoryCacheConfig),
439 {
440 f(&mut self.fee_history_cache_config);
441 self
442 }
443
444 pub fn modify_eth_state_cache_config<F>(mut self, f: F) -> Self
446 where
447 F: FnOnce(&mut EthStateCacheConfig),
448 {
449 f(&mut self.eth_state_cache_config);
450 self
451 }
452
453 pub fn modify_gas_oracle_config<F>(mut self, f: F) -> Self
455 where
456 F: FnOnce(&mut GasPriceOracleConfig),
457 {
458 f(&mut self.gas_oracle_config);
459 self
460 }
461
462 pub fn modify_raw_tx_forwarder<F>(mut self, f: F) -> Self
464 where
465 F: FnOnce(&mut ForwardConfig),
466 {
467 f(&mut self.raw_tx_forwarder);
468 self
469 }
470
471 pub fn build_inner(self) -> EthApiInner<N, Rpc>
480 where
481 Rpc: RpcConvert,
482 NextEnv: PendingEnvBuilder<N::Evm>,
483 {
484 let Self {
485 components,
486 rpc_converter,
487 eth_state_cache_config,
488 gas_oracle_config,
489 eth_cache,
490 gas_oracle,
491 gas_cap,
492 max_simulate_blocks,
493 eth_proof_window,
494 blocking_task_pool,
495 fee_history_cache_config,
496 proof_permits,
497 task_spawner,
498 next_env,
499 max_batch_size,
500 max_blocking_io_requests,
501 pending_block_kind,
502 raw_tx_forwarder,
503 send_raw_transaction_sync_timeout,
504 evm_memory_limit,
505 } = self;
506
507 let provider = components.provider().clone();
508
509 let eth_cache = eth_cache
510 .unwrap_or_else(|| EthStateCache::spawn(provider.clone(), eth_state_cache_config));
511 let gas_oracle = gas_oracle.unwrap_or_else(|| {
512 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
513 });
514 let fee_history_cache =
515 FeeHistoryCache::<HeaderTy<N::Primitives>>::new(fee_history_cache_config);
516 let new_canonical_blocks = provider.canonical_state_stream();
517 let fhc = fee_history_cache.clone();
518 let cache = eth_cache.clone();
519 task_spawner.spawn_critical(
520 "cache canonical blocks for fee history task",
521 Box::pin(async move {
522 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, provider, cache).await;
523 }),
524 );
525
526 EthApiInner::new(
527 components,
528 eth_cache,
529 gas_oracle,
530 gas_cap,
531 max_simulate_blocks,
532 eth_proof_window,
533 blocking_task_pool.unwrap_or_else(|| {
534 BlockingTaskPool::build().expect("failed to build blocking task pool")
535 }),
536 fee_history_cache,
537 task_spawner,
538 proof_permits,
539 rpc_converter,
540 next_env,
541 max_batch_size,
542 max_blocking_io_requests,
543 pending_block_kind,
544 raw_tx_forwarder.forwarder_client(),
545 send_raw_transaction_sync_timeout,
546 evm_memory_limit,
547 )
548 }
549
550 pub fn build(self) -> EthApi<N, Rpc>
559 where
560 Rpc: RpcConvert,
561 NextEnv: PendingEnvBuilder<N::Evm>,
562 {
563 EthApi { inner: Arc::new(self.build_inner()) }
564 }
565
566 pub const fn send_raw_transaction_sync_timeout(mut self, timeout: Duration) -> Self {
568 self.send_raw_transaction_sync_timeout = timeout;
569 self
570 }
571
572 pub const fn evm_memory_limit(mut self, memory_limit: u64) -> Self {
574 self.evm_memory_limit = memory_limit;
575 self
576 }
577}