1use crate::{eth::core::EthApiInner, EthApi};
4use alloy_network::Ethereum;
5use reth_chain_state::CanonStateSubscriptions;
6use reth_chainspec::ChainSpecProvider;
7use reth_evm::ConfigureEvm;
8use reth_node_api::NodePrimitives;
9use reth_rpc_convert::{RpcConvert, RpcConverter};
10use reth_rpc_eth_api::helpers::pending_block::{BasicPendingEnvBuilder, PendingEnvBuilder};
11use reth_rpc_eth_types::{
12 fee_history::fee_history_cache_new_blocks_task, receipt::EthReceiptConverter, EthStateCache,
13 EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasCap, GasPriceOracle,
14 GasPriceOracleConfig,
15};
16use reth_rpc_server_types::constants::{
17 DEFAULT_ETH_PROOF_WINDOW, DEFAULT_MAX_SIMULATE_BLOCKS, DEFAULT_PROOF_PERMITS,
18};
19use reth_storage_api::{BlockReaderIdExt, StateProviderFactory};
20use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor};
21use std::sync::Arc;
22
23#[derive(Debug)]
28pub struct EthApiBuilder<Provider, Pool, Network, EvmConfig, Rpc, NextEnv = BasicPendingEnvBuilder>
29where
30 Provider: BlockReaderIdExt,
31{
32 provider: Provider,
33 pool: Pool,
34 network: Network,
35 evm_config: EvmConfig,
36 rpc_converter: Rpc,
37 gas_cap: GasCap,
38 max_simulate_blocks: u64,
39 eth_proof_window: u64,
40 fee_history_cache_config: FeeHistoryCacheConfig,
41 proof_permits: usize,
42 eth_state_cache_config: EthStateCacheConfig,
43 eth_cache: Option<EthStateCache<Provider::Block, Provider::Receipt>>,
44 gas_oracle_config: GasPriceOracleConfig,
45 gas_oracle: Option<GasPriceOracle<Provider>>,
46 blocking_task_pool: Option<BlockingTaskPool>,
47 task_spawner: Box<dyn TaskSpawner + 'static>,
48 next_env: NextEnv,
49}
50
51impl<Provider, Pool, Network, EvmConfig>
52 EthApiBuilder<
53 Provider,
54 Pool,
55 Network,
56 EvmConfig,
57 RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<Provider::ChainSpec>>,
58 >
59where
60 Provider: BlockReaderIdExt + ChainSpecProvider,
61{
62 pub fn new(provider: Provider, pool: Pool, network: Network, evm_config: EvmConfig) -> Self
64 where
65 Provider: BlockReaderIdExt,
66 {
67 let rpc_converter = RpcConverter::new(EthReceiptConverter::new(provider.chain_spec()), ());
68 Self {
69 provider,
70 pool,
71 network,
72 evm_config,
73 rpc_converter,
74 eth_cache: None,
75 gas_oracle: None,
76 gas_cap: GasCap::default(),
77 max_simulate_blocks: DEFAULT_MAX_SIMULATE_BLOCKS,
78 eth_proof_window: DEFAULT_ETH_PROOF_WINDOW,
79 blocking_task_pool: None,
80 fee_history_cache_config: FeeHistoryCacheConfig::default(),
81 proof_permits: DEFAULT_PROOF_PERMITS,
82 task_spawner: TokioTaskExecutor::default().boxed(),
83 gas_oracle_config: Default::default(),
84 eth_state_cache_config: Default::default(),
85 next_env: BasicPendingEnvBuilder::default(),
86 }
87 }
88}
89
90impl<Provider, Pool, Network, EvmConfig, Rpc, NextEnv>
91 EthApiBuilder<Provider, Pool, Network, EvmConfig, Rpc, NextEnv>
92where
93 Provider: BlockReaderIdExt + ChainSpecProvider,
94{
95 pub fn task_spawner(mut self, spawner: impl TaskSpawner + 'static) -> Self {
97 self.task_spawner = Box::new(spawner);
98 self
99 }
100
101 pub fn with_rpc_converter<RpcNew>(
103 self,
104 rpc_converter: RpcNew,
105 ) -> EthApiBuilder<Provider, Pool, Network, EvmConfig, RpcNew, NextEnv> {
106 let Self {
107 provider,
108 pool,
109 network,
110 evm_config,
111 rpc_converter: _,
112 gas_cap,
113 max_simulate_blocks,
114 eth_proof_window,
115 fee_history_cache_config,
116 proof_permits,
117 eth_state_cache_config,
118 eth_cache,
119 gas_oracle,
120 blocking_task_pool,
121 task_spawner,
122 gas_oracle_config,
123 next_env,
124 } = self;
125 EthApiBuilder {
126 provider,
127 pool,
128 network,
129 evm_config,
130 rpc_converter,
131 gas_cap,
132 max_simulate_blocks,
133 eth_proof_window,
134 fee_history_cache_config,
135 proof_permits,
136 eth_state_cache_config,
137 eth_cache,
138 gas_oracle,
139 blocking_task_pool,
140 task_spawner,
141 gas_oracle_config,
142 next_env,
143 }
144 }
145
146 pub fn with_pending_env_builder<NextEnvNew>(
148 self,
149 next_env: NextEnvNew,
150 ) -> EthApiBuilder<Provider, Pool, Network, EvmConfig, Rpc, NextEnvNew> {
151 let Self {
152 provider,
153 pool,
154 network,
155 evm_config,
156 rpc_converter,
157 gas_cap,
158 max_simulate_blocks,
159 eth_proof_window,
160 fee_history_cache_config,
161 proof_permits,
162 eth_state_cache_config,
163 eth_cache,
164 gas_oracle,
165 blocking_task_pool,
166 task_spawner,
167 gas_oracle_config,
168 next_env: _,
169 } = self;
170 EthApiBuilder {
171 provider,
172 pool,
173 network,
174 evm_config,
175 rpc_converter,
176 gas_cap,
177 max_simulate_blocks,
178 eth_proof_window,
179 fee_history_cache_config,
180 proof_permits,
181 eth_state_cache_config,
182 eth_cache,
183 gas_oracle,
184 blocking_task_pool,
185 task_spawner,
186 gas_oracle_config,
187 next_env,
188 }
189 }
190
191 pub const fn eth_state_cache_config(
194 mut self,
195 eth_state_cache_config: EthStateCacheConfig,
196 ) -> Self {
197 self.eth_state_cache_config = eth_state_cache_config;
198 self
199 }
200
201 pub fn eth_cache(
203 mut self,
204 eth_cache: EthStateCache<Provider::Block, Provider::Receipt>,
205 ) -> Self {
206 self.eth_cache = Some(eth_cache);
207 self
208 }
209
210 pub const fn gas_oracle_config(mut self, gas_oracle_config: GasPriceOracleConfig) -> Self {
213 self.gas_oracle_config = gas_oracle_config;
214 self
215 }
216
217 pub fn gas_oracle(mut self, gas_oracle: GasPriceOracle<Provider>) -> Self {
219 self.gas_oracle = Some(gas_oracle);
220 self
221 }
222
223 pub const fn gas_cap(mut self, gas_cap: GasCap) -> Self {
225 self.gas_cap = gas_cap;
226 self
227 }
228
229 pub const fn max_simulate_blocks(mut self, max_simulate_blocks: u64) -> Self {
231 self.max_simulate_blocks = max_simulate_blocks;
232 self
233 }
234
235 pub const fn eth_proof_window(mut self, eth_proof_window: u64) -> Self {
237 self.eth_proof_window = eth_proof_window;
238 self
239 }
240
241 pub fn blocking_task_pool(mut self, blocking_task_pool: BlockingTaskPool) -> Self {
243 self.blocking_task_pool = Some(blocking_task_pool);
244 self
245 }
246
247 pub const fn fee_history_cache_config(
249 mut self,
250 fee_history_cache_config: FeeHistoryCacheConfig,
251 ) -> Self {
252 self.fee_history_cache_config = fee_history_cache_config;
253 self
254 }
255
256 pub const fn proof_permits(mut self, proof_permits: usize) -> Self {
258 self.proof_permits = proof_permits;
259 self
260 }
261
262 pub fn build_inner(self) -> EthApiInner<Provider, Pool, Network, EvmConfig, Rpc>
271 where
272 Provider: BlockReaderIdExt
273 + StateProviderFactory
274 + ChainSpecProvider
275 + CanonStateSubscriptions<
276 Primitives: NodePrimitives<
277 Block = Provider::Block,
278 Receipt = Provider::Receipt,
279 BlockHeader = Provider::Header,
280 >,
281 > + Clone
282 + Unpin
283 + 'static,
284 EvmConfig: ConfigureEvm,
285 Rpc: RpcConvert,
286 NextEnv: PendingEnvBuilder<EvmConfig>,
287 {
288 let Self {
289 provider,
290 pool,
291 network,
292 evm_config,
293 rpc_converter,
294 eth_state_cache_config,
295 gas_oracle_config,
296 eth_cache,
297 gas_oracle,
298 gas_cap,
299 max_simulate_blocks,
300 eth_proof_window,
301 blocking_task_pool,
302 fee_history_cache_config,
303 proof_permits,
304 task_spawner,
305 next_env,
306 } = self;
307
308 let eth_cache = eth_cache
309 .unwrap_or_else(|| EthStateCache::spawn(provider.clone(), eth_state_cache_config));
310 let gas_oracle = gas_oracle.unwrap_or_else(|| {
311 GasPriceOracle::new(provider.clone(), gas_oracle_config, eth_cache.clone())
312 });
313 let fee_history_cache = FeeHistoryCache::<Provider::Header>::new(fee_history_cache_config);
314 let new_canonical_blocks = provider.canonical_state_stream();
315 let fhc = fee_history_cache.clone();
316 let cache = eth_cache.clone();
317 let prov = provider.clone();
318 task_spawner.spawn_critical(
319 "cache canonical blocks for fee history task",
320 Box::pin(async move {
321 fee_history_cache_new_blocks_task(fhc, new_canonical_blocks, prov, cache).await;
322 }),
323 );
324
325 EthApiInner::new(
326 provider,
327 pool,
328 network,
329 eth_cache,
330 gas_oracle,
331 gas_cap,
332 max_simulate_blocks,
333 eth_proof_window,
334 blocking_task_pool.unwrap_or_else(|| {
335 BlockingTaskPool::build().expect("failed to build blocking task pool")
336 }),
337 fee_history_cache,
338 evm_config,
339 task_spawner,
340 proof_permits,
341 rpc_converter,
342 next_env,
343 )
344 }
345
346 pub fn build(self) -> EthApi<Provider, Pool, Network, EvmConfig, Rpc>
355 where
356 Provider: BlockReaderIdExt
357 + StateProviderFactory
358 + CanonStateSubscriptions<
359 Primitives: NodePrimitives<
360 Block = Provider::Block,
361 Receipt = Provider::Receipt,
362 BlockHeader = Provider::Header,
363 >,
364 > + ChainSpecProvider
365 + Clone
366 + Unpin
367 + 'static,
368 Rpc: RpcConvert,
369 EvmConfig: ConfigureEvm,
370 NextEnv: PendingEnvBuilder<EvmConfig>,
371 {
372 EthApi { inner: Arc::new(self.build_inner()) }
373 }
374}