1pub use crate::{payload::EthereumPayloadBuilder, EthereumEngineValidator};
4use crate::{EthEngineTypes, EthEvmConfig};
5use alloy_eips::{eip7840::BlobParams, merge::EPOCH_SLOTS};
6use alloy_rpc_types_engine::ExecutionData;
7use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, Hardforks};
8use reth_consensus::{ConsensusError, FullConsensus};
9use reth_engine_primitives::EngineTypes;
10use reth_ethereum_consensus::EthBeaconConsensus;
11use reth_ethereum_engine_primitives::{
12 EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes,
13};
14use reth_ethereum_primitives::{EthPrimitives, TransactionSigned};
15use reth_evm::{ConfigureEvm, EvmFactory, EvmFactoryFor, NextBlockEnvAttributes};
16use reth_network::{primitives::BasicNetworkPrimitives, NetworkHandle, PeersInfo};
17use reth_node_api::{
18 AddOnsContext, FullNodeComponents, NodeAddOns, NodePrimitives, PrimitivesTy, TxTy,
19};
20use reth_node_builder::{
21 components::{
22 BasicPayloadServiceBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder,
23 NetworkBuilder, PoolBuilder, TxPoolBuilder,
24 },
25 node::{FullNodeTypes, NodeTypes},
26 rpc::{
27 BasicEngineApiBuilder, EngineApiBuilder, EngineValidatorAddOn, EngineValidatorBuilder,
28 EthApiBuilder, EthApiCtx, RethRpcAddOns, RpcAddOns, RpcHandle,
29 },
30 BuilderContext, DebugNode, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig,
31 PayloadTypes,
32};
33use reth_provider::{providers::ProviderFactoryBuilder, EthStorage};
34use reth_rpc::{eth::core::EthApiFor, ValidationApi};
35use reth_rpc_api::{eth::FullEthApiServer, servers::BlockSubmissionValidationApiServer};
36use reth_rpc_builder::config::RethRpcServerConfig;
37use reth_rpc_eth_types::{error::FromEvmError, EthApiError};
38use reth_rpc_server_types::RethRpcModule;
39use reth_tracing::tracing::{debug, info};
40use reth_transaction_pool::{
41 blobstore::DiskFileBlobStore, EthTransactionPool, PoolPooledTx, PoolTransaction,
42 TransactionPool, TransactionValidationTaskExecutor,
43};
44use reth_trie_db::MerklePatriciaTrie;
45use revm::context::TxEnv;
46use std::{default::Default, sync::Arc, time::SystemTime};
47
48#[derive(Debug, Default, Clone, Copy)]
50#[non_exhaustive]
51pub struct EthereumNode;
52
53impl EthereumNode {
54 pub fn components<Node>() -> ComponentsBuilder<
56 Node,
57 EthereumPoolBuilder,
58 BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
59 EthereumNetworkBuilder,
60 EthereumExecutorBuilder,
61 EthereumConsensusBuilder,
62 >
63 where
64 Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
65 <Node::Types as NodeTypes>::Payload: PayloadTypes<
66 BuiltPayload = EthBuiltPayload,
67 PayloadAttributes = EthPayloadAttributes,
68 PayloadBuilderAttributes = EthPayloadBuilderAttributes,
69 >,
70 {
71 ComponentsBuilder::default()
72 .node_types::<Node>()
73 .pool(EthereumPoolBuilder::default())
74 .executor(EthereumExecutorBuilder::default())
75 .payload(BasicPayloadServiceBuilder::default())
76 .network(EthereumNetworkBuilder::default())
77 .consensus(EthereumConsensusBuilder::default())
78 }
79
80 pub fn provider_factory_builder() -> ProviderFactoryBuilder<Self> {
112 ProviderFactoryBuilder::default()
113 }
114}
115
116impl NodeTypes for EthereumNode {
117 type Primitives = EthPrimitives;
118 type ChainSpec = ChainSpec;
119 type StateCommitment = MerklePatriciaTrie;
120 type Storage = EthStorage;
121 type Payload = EthEngineTypes;
122}
123
124#[derive(Debug, Default)]
126pub struct EthereumEthApiBuilder;
127
128impl<N> EthApiBuilder<N> for EthereumEthApiBuilder
129where
130 N: FullNodeComponents,
131 EthApiFor<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
132{
133 type EthApi = EthApiFor<N>;
134
135 async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
136 let api = reth_rpc::EthApiBuilder::new(
137 ctx.components.provider().clone(),
138 ctx.components.pool().clone(),
139 ctx.components.network().clone(),
140 ctx.components.evm_config().clone(),
141 )
142 .eth_cache(ctx.cache)
143 .task_spawner(ctx.components.task_executor().clone())
144 .gas_cap(ctx.config.rpc_gas_cap.into())
145 .max_simulate_blocks(ctx.config.rpc_max_simulate_blocks)
146 .eth_proof_window(ctx.config.eth_proof_window)
147 .fee_history_cache_config(ctx.config.fee_history_cache)
148 .proof_permits(ctx.config.proof_permits)
149 .gas_oracle_config(ctx.config.gas_oracle)
150 .build();
151 Ok(api)
152 }
153}
154
155#[derive(Debug)]
157pub struct EthereumAddOns<
158 N: FullNodeComponents,
159 EthB: EthApiBuilder<N>,
160 EV,
161 EB = BasicEngineApiBuilder<EV>,
162> {
163 inner: RpcAddOns<N, EthB, EV, EB>,
164}
165
166impl<N> Default for EthereumAddOns<N, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>
167where
168 N: FullNodeComponents,
169 EthereumEthApiBuilder: EthApiBuilder<N>,
170{
171 fn default() -> Self {
172 Self {
173 inner: RpcAddOns::new(
174 EthereumEthApiBuilder,
175 EthereumEngineValidatorBuilder::default(),
176 BasicEngineApiBuilder::default(),
177 ),
178 }
179 }
180}
181
182impl<N, EthB, EV, EB> EthereumAddOns<N, EthB, EV, EB>
183where
184 N: FullNodeComponents,
185 EthB: EthApiBuilder<N>,
186{
187 pub fn with_engine_api<T>(self, engine_api_builder: T) -> EthereumAddOns<N, EthB, EV, T>
189 where
190 T: Send,
191 {
192 let Self { inner } = self;
193 EthereumAddOns { inner: inner.with_engine_api(engine_api_builder) }
194 }
195
196 pub fn with_engine_validator<T>(
198 self,
199 engine_validator_builder: T,
200 ) -> EthereumAddOns<N, EthB, T, EB>
201 where
202 T: Send,
203 {
204 let Self { inner } = self;
205 EthereumAddOns { inner: inner.with_engine_validator(engine_validator_builder) }
206 }
207}
208
209impl<N, EthB, EV, EB> NodeAddOns<N> for EthereumAddOns<N, EthB, EV, EB>
210where
211 N: FullNodeComponents<
212 Types: NodeTypes<
213 ChainSpec: EthChainSpec + EthereumHardforks,
214 Primitives = EthPrimitives,
215 Payload: EngineTypes<ExecutionData = ExecutionData>,
216 >,
217 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
218 >,
219 EthB: EthApiBuilder<N>,
220 EV: EngineValidatorBuilder<N>,
221 EB: EngineApiBuilder<N>,
222 EthApiError: FromEvmError<N::Evm>,
223 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
224{
225 type Handle = RpcHandle<N, EthB::EthApi>;
226
227 async fn launch_add_ons(
228 self,
229 ctx: reth_node_api::AddOnsContext<'_, N>,
230 ) -> eyre::Result<Self::Handle> {
231 let validation_api = ValidationApi::new(
232 ctx.node.provider().clone(),
233 Arc::new(ctx.node.consensus().clone()),
234 ctx.node.evm_config().clone(),
235 ctx.config.rpc.flashbots_config(),
236 Box::new(ctx.node.task_executor().clone()),
237 Arc::new(EthereumEngineValidator::new(ctx.config.chain.clone())),
238 );
239
240 self.inner
241 .launch_add_ons_with(ctx, move |container| {
242 container.modules.merge_if_module_configured(
243 RethRpcModule::Flashbots,
244 validation_api.into_rpc(),
245 )?;
246
247 Ok(())
248 })
249 .await
250 }
251}
252
253impl<N, EthB, EV, EB> RethRpcAddOns<N> for EthereumAddOns<N, EthB, EV, EB>
254where
255 N: FullNodeComponents<
256 Types: NodeTypes<
257 ChainSpec: EthChainSpec + EthereumHardforks,
258 Primitives = EthPrimitives,
259 Payload: EngineTypes<ExecutionData = ExecutionData>,
260 >,
261 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
262 >,
263 EthB: EthApiBuilder<N>,
264 EV: EngineValidatorBuilder<N>,
265 EB: EngineApiBuilder<N>,
266 EthApiError: FromEvmError<N::Evm>,
267 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
268{
269 type EthApi = EthB::EthApi;
270
271 fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks<N, Self::EthApi> {
272 self.inner.hooks_mut()
273 }
274}
275
276impl<N, EthB, EV, EB> EngineValidatorAddOn<N> for EthereumAddOns<N, EthB, EV, EB>
277where
278 N: FullNodeComponents<
279 Types: NodeTypes<
280 ChainSpec: EthChainSpec + EthereumHardforks,
281 Primitives = EthPrimitives,
282 Payload: EngineTypes<ExecutionData = ExecutionData>,
283 >,
284 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
285 >,
286 EthB: EthApiBuilder<N>,
287 EV: EngineValidatorBuilder<N>,
288 EB: EngineApiBuilder<N>,
289 EthApiError: FromEvmError<N::Evm>,
290 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
291{
292 type Validator = EV::Validator;
293
294 async fn engine_validator(&self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::Validator> {
295 self.inner.engine_validator(ctx).await
296 }
297}
298
299impl<N> Node<N> for EthereumNode
300where
301 N: FullNodeTypes<Types = Self>,
302{
303 type ComponentsBuilder = ComponentsBuilder<
304 N,
305 EthereumPoolBuilder,
306 BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
307 EthereumNetworkBuilder,
308 EthereumExecutorBuilder,
309 EthereumConsensusBuilder,
310 >;
311
312 type AddOns = EthereumAddOns<
313 NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
314 EthereumEthApiBuilder,
315 EthereumEngineValidatorBuilder<ChainSpec>,
316 >;
317
318 fn components_builder(&self) -> Self::ComponentsBuilder {
319 Self::components()
320 }
321
322 fn add_ons(&self) -> Self::AddOns {
323 EthereumAddOns::default()
324 }
325}
326
327impl<N: FullNodeComponents<Types = Self>> DebugNode<N> for EthereumNode {
328 type RpcBlock = alloy_rpc_types_eth::Block;
329
330 fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> reth_ethereum_primitives::Block {
331 rpc_block.into_consensus().convert_transactions()
332 }
333}
334
335#[derive(Debug, Default, Clone, Copy)]
337#[non_exhaustive]
338pub struct EthereumExecutorBuilder;
339
340impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
341where
342 Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
343 Node: FullNodeTypes<Types = Types>,
344{
345 type EVM = EthEvmConfig;
346
347 async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
348 let evm_config = EthEvmConfig::new(ctx.chain_spec())
349 .with_extra_data(ctx.payload_builder_config().extra_data_bytes());
350 Ok(evm_config)
351 }
352}
353
354#[derive(Debug, Default, Clone, Copy)]
359#[non_exhaustive]
360pub struct EthereumPoolBuilder {
361 }
363
364impl<Types, Node> PoolBuilder<Node> for EthereumPoolBuilder
365where
366 Types: NodeTypes<
367 ChainSpec: EthereumHardforks,
368 Primitives: NodePrimitives<SignedTx = TransactionSigned>,
369 >,
370 Node: FullNodeTypes<Types = Types>,
371{
372 type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore>;
373
374 async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
375 let pool_config = ctx.pool_config();
376
377 let blob_cache_size = if let Some(blob_cache_size) = pool_config.blob_cache_size {
378 Some(blob_cache_size)
379 } else {
380 let current_timestamp =
383 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
384 let blob_params = ctx
385 .chain_spec()
386 .blob_params_at_timestamp(current_timestamp)
387 .unwrap_or_else(BlobParams::cancun);
388
389 Some((blob_params.target_blob_count * EPOCH_SLOTS * 2) as u32)
392 };
393
394 let blob_store =
395 reth_node_builder::components::create_blob_store_with_cache(ctx, blob_cache_size)?;
396
397 let validator = TransactionValidationTaskExecutor::eth_builder(ctx.provider().clone())
398 .with_head_timestamp(ctx.head().timestamp)
399 .kzg_settings(ctx.kzg_settings()?)
400 .with_local_transactions_config(pool_config.local_transactions_config.clone())
401 .set_tx_fee_cap(ctx.config().rpc.rpc_tx_fee_cap)
402 .with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
403 .build_with_tasks(ctx.task_executor().clone(), blob_store.clone());
404
405 let transaction_pool = TxPoolBuilder::new(ctx)
406 .with_validator(validator)
407 .build_and_spawn_maintenance_task(blob_store, pool_config)?;
408
409 info!(target: "reth::cli", "Transaction pool initialized");
410 debug!(target: "reth::cli", "Spawned txpool maintenance task");
411
412 Ok(transaction_pool)
413 }
414}
415
416#[derive(Debug, Default, Clone, Copy)]
418pub struct EthereumNetworkBuilder {
419 }
421
422impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetworkBuilder
423where
424 Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>,
425 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
426 + Unpin
427 + 'static,
428{
429 type Network =
430 NetworkHandle<BasicNetworkPrimitives<PrimitivesTy<Node::Types>, PoolPooledTx<Pool>>>;
431
432 async fn build_network(
433 self,
434 ctx: &BuilderContext<Node>,
435 pool: Pool,
436 ) -> eyre::Result<Self::Network> {
437 let network = ctx.network_builder().await?;
438 let handle = ctx.start_network(network, pool);
439 info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
440 Ok(handle)
441 }
442}
443
444#[derive(Debug, Default, Clone, Copy)]
446pub struct EthereumConsensusBuilder {
447 }
449
450impl<Node> ConsensusBuilder<Node> for EthereumConsensusBuilder
451where
452 Node: FullNodeTypes<
453 Types: NodeTypes<ChainSpec: EthChainSpec + EthereumHardforks, Primitives = EthPrimitives>,
454 >,
455{
456 type Consensus = Arc<dyn FullConsensus<EthPrimitives, Error = ConsensusError>>;
457
458 async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
459 Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
460 }
461}
462
463#[derive(Debug, Default, Clone)]
465#[non_exhaustive]
466pub struct EthereumEngineValidatorBuilder<ChainSpec = reth_chainspec::ChainSpec> {
467 _phantom: std::marker::PhantomData<ChainSpec>,
468}
469
470impl<Node, Types, ChainSpec> EngineValidatorBuilder<Node>
471 for EthereumEngineValidatorBuilder<ChainSpec>
472where
473 Types: NodeTypes<
474 ChainSpec = ChainSpec,
475 Payload: EngineTypes<ExecutionData = ExecutionData>
476 + PayloadTypes<PayloadAttributes = EthPayloadAttributes>,
477 Primitives = EthPrimitives,
478 >,
479 Node: FullNodeComponents<Types = Types>,
480 ChainSpec: EthChainSpec + EthereumHardforks + Clone + 'static,
481{
482 type Validator = EthereumEngineValidator<ChainSpec>;
483
484 async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
485 Ok(EthereumEngineValidator::new(ctx.config.chain.clone()))
486 }
487}