1pub use crate::{payload::EthereumPayloadBuilder, EthereumEngineValidator};
4use crate::{EthEngineTypes, EthEvmConfig};
5use alloy_eips::{eip7840::BlobParams, merge::EPOCH_SLOTS};
6use alloy_network::Ethereum;
7use alloy_rpc_types_engine::ExecutionData;
8use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, Hardforks};
9use reth_engine_local::LocalPayloadAttributesBuilder;
10use reth_engine_primitives::EngineTypes;
11use reth_ethereum_consensus::EthBeaconConsensus;
12use reth_ethereum_engine_primitives::{EthBuiltPayload, EthPayloadAttributes};
13use reth_ethereum_primitives::{EthPrimitives, TransactionSigned};
14use reth_evm::{
15 eth::spec::EthExecutorSpec, ConfigureEvm, EvmFactory, EvmFactoryFor, NextBlockEnvAttributes,
16};
17use reth_network::{primitives::BasicNetworkPrimitives, NetworkHandle, PeersInfo};
18use reth_node_api::{
19 AddOnsContext, FullNodeComponents, HeaderTy, NodeAddOns, NodePrimitives,
20 PayloadAttributesBuilder, PrimitivesTy, TxTy,
21};
22use reth_node_builder::{
23 components::{
24 BasicPayloadServiceBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder,
25 NetworkBuilder, PoolBuilder, TxPoolBuilder,
26 },
27 node::{FullNodeTypes, NodeTypes},
28 rpc::{
29 BasicEngineApiBuilder, BasicEngineValidatorBuilder, Either, EngineApiBuilder,
30 EngineValidatorAddOn, EngineValidatorBuilder, EthApiBuilder, EthApiCtx, Identity,
31 PayloadValidatorBuilder, RethAuthHttpMiddleware, RethRpcAddOns, RethRpcMiddleware,
32 RpcAddOns, RpcHandle, Stack,
33 },
34 BuilderContext, DebugNode, Node, NodeAdapter,
35};
36use reth_payload_primitives::PayloadTypes;
37use reth_provider::{providers::ProviderFactoryBuilder, EthStorage};
38use reth_rpc::{
39 eth::core::{EthApiFor, EthRpcConverterFor},
40 TestingApi, ValidationApi,
41};
42use reth_rpc_api::servers::{BlockSubmissionValidationApiServer, TestingApiServer};
43use reth_rpc_builder::config::RethRpcServerConfig;
44use reth_rpc_eth_api::{
45 helpers::{
46 config::{EthConfigApiServer, EthConfigHandler},
47 pending_block::BuildPendingEnv,
48 },
49 RpcConvert, RpcTypes, SignableTxRequest,
50};
51use reth_rpc_eth_types::{error::FromEvmError, EthApiError};
52use reth_rpc_server_types::RethRpcModule;
53use reth_tracing::tracing::{debug, info};
54use reth_transaction_pool::{
55 blobstore::DiskFileBlobStore, EthTransactionPool, PoolPooledTx, PoolTransaction,
56 TransactionPool, TransactionValidationTaskExecutor,
57};
58use revm::context::TxEnv;
59use std::{marker::PhantomData, sync::Arc, time::SystemTime};
60
61#[derive(Debug, Default, Clone, Copy)]
63#[non_exhaustive]
64pub struct EthereumNode;
65
66impl EthereumNode {
67 pub fn components<Node>() -> ComponentsBuilder<
69 Node,
70 EthereumPoolBuilder,
71 BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
72 EthereumNetworkBuilder,
73 EthereumExecutorBuilder,
74 EthereumConsensusBuilder,
75 >
76 where
77 Node: FullNodeTypes<
78 Types: NodeTypes<
79 ChainSpec: Hardforks + EthereumHardforks + EthExecutorSpec,
80 Primitives = EthPrimitives,
81 >,
82 >,
83 <Node::Types as NodeTypes>::Payload:
84 PayloadTypes<BuiltPayload = EthBuiltPayload, PayloadAttributes = EthPayloadAttributes>,
85 {
86 ComponentsBuilder::default()
87 .node_types::<Node>()
88 .pool(EthereumPoolBuilder::default())
89 .executor(EthereumExecutorBuilder::default())
90 .payload(BasicPayloadServiceBuilder::default())
91 .network(EthereumNetworkBuilder::default())
92 .consensus(EthereumConsensusBuilder::default())
93 }
94
95 pub fn provider_factory_builder() -> ProviderFactoryBuilder<Self> {
117 ProviderFactoryBuilder::default()
118 }
119}
120
121impl NodeTypes for EthereumNode {
122 type Primitives = EthPrimitives;
123 type ChainSpec = ChainSpec;
124 type Storage = EthStorage;
125 type Payload = EthEngineTypes;
126}
127
128#[derive(Debug)]
130pub struct EthereumEthApiBuilder<NetworkT = Ethereum>(PhantomData<NetworkT>);
131
132impl<NetworkT> Default for EthereumEthApiBuilder<NetworkT> {
133 fn default() -> Self {
134 Self(Default::default())
135 }
136}
137
138impl<N, NetworkT> EthApiBuilder<N> for EthereumEthApiBuilder<NetworkT>
139where
140 N: FullNodeComponents<
141 Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>,
142 Evm: ConfigureEvm<NextBlockEnvCtx: BuildPendingEnv<HeaderTy<N::Types>>>,
143 >,
144 NetworkT: RpcTypes<TransactionRequest: SignableTxRequest<TxTy<N::Types>>>,
145 EthRpcConverterFor<N, NetworkT>: RpcConvert<
146 Primitives = PrimitivesTy<N::Types>,
147 Error = EthApiError,
148 Network = NetworkT,
149 Evm = N::Evm,
150 >,
151 EthApiError: FromEvmError<N::Evm>,
152{
153 type EthApi = EthApiFor<N, NetworkT>;
154
155 async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
156 Ok(ctx.eth_api_builder().map_converter(|r| r.with_network()).build())
157 }
158}
159
160#[derive(Debug)]
162pub struct EthereumAddOns<
163 N: FullNodeComponents,
164 EthB: EthApiBuilder<N>,
165 PVB,
166 EB = BasicEngineApiBuilder<PVB>,
167 EVB = BasicEngineValidatorBuilder<PVB>,
168 RpcMiddleware = Identity,
169 AuthHttpMiddleware = Identity,
170> {
171 inner: RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>,
172}
173
174impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
175 EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
176where
177 N: FullNodeComponents,
178 EthB: EthApiBuilder<N>,
179{
180 pub const fn new(
182 inner: RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>,
183 ) -> Self {
184 Self { inner }
185 }
186}
187
188impl<N> Default for EthereumAddOns<N, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>
189where
190 N: FullNodeComponents<
191 Types: NodeTypes<
192 ChainSpec: EthereumHardforks + Clone + 'static,
193 Payload: EngineTypes<ExecutionData = ExecutionData>
194 + PayloadTypes<PayloadAttributes = EthPayloadAttributes>,
195 Primitives = EthPrimitives,
196 >,
197 >,
198 EthereumEthApiBuilder: EthApiBuilder<N>,
199{
200 fn default() -> Self {
201 Self::new(RpcAddOns::new(
202 EthereumEthApiBuilder::default(),
203 EthereumEngineValidatorBuilder::default(),
204 BasicEngineApiBuilder::default(),
205 BasicEngineValidatorBuilder::default(),
206 Default::default(),
207 Identity::new(),
208 ))
209 }
210}
211
212impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
213 EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
214where
215 N: FullNodeComponents,
216 EthB: EthApiBuilder<N>,
217{
218 pub fn with_engine_api<T>(
220 self,
221 engine_api_builder: T,
222 ) -> EthereumAddOns<N, EthB, PVB, T, EVB, RpcMiddleware, AuthHttpMiddleware>
223 where
224 T: Send,
225 {
226 let Self { inner } = self;
227 EthereumAddOns::new(inner.with_engine_api(engine_api_builder))
228 }
229
230 pub fn with_payload_validator<V, T>(
232 self,
233 payload_validator_builder: T,
234 ) -> EthereumAddOns<N, EthB, T, EB, EVB, RpcMiddleware, AuthHttpMiddleware> {
235 let Self { inner } = self;
236 EthereumAddOns::new(inner.with_payload_validator(payload_validator_builder))
237 }
238
239 pub fn with_rpc_middleware<T>(
241 self,
242 rpc_middleware: T,
243 ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, T, AuthHttpMiddleware>
244 where
245 T: Send,
246 {
247 let Self { inner } = self;
248 EthereumAddOns::new(inner.with_rpc_middleware(rpc_middleware))
249 }
250
251 pub fn with_auth_http_middleware<T>(
253 self,
254 auth_http_middleware: T,
255 ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, T>
256 where
257 T: Send,
258 {
259 let Self { inner } = self;
260 EthereumAddOns::new(inner.with_auth_http_middleware(auth_http_middleware))
261 }
262
263 pub fn layer_auth_http_middleware<T>(
265 self,
266 layer: T,
267 ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, Stack<AuthHttpMiddleware, T>> {
268 let Self { inner } = self;
269 EthereumAddOns::new(inner.layer_auth_http_middleware(layer))
270 }
271
272 #[expect(clippy::type_complexity)]
274 pub fn option_layer_auth_http_middleware<T>(
275 self,
276 layer: Option<T>,
277 ) -> EthereumAddOns<
278 N,
279 EthB,
280 PVB,
281 EB,
282 EVB,
283 RpcMiddleware,
284 Stack<AuthHttpMiddleware, Either<T, Identity>>,
285 > {
286 let Self { inner } = self;
287 EthereumAddOns::new(inner.option_layer_auth_http_middleware(layer))
288 }
289
290 pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
294 let Self { inner } = self;
295 Self { inner: inner.with_tokio_runtime(tokio_runtime) }
296 }
297}
298
299impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> NodeAddOns<N>
300 for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
301where
302 N: FullNodeComponents<
303 Types: NodeTypes<
304 ChainSpec: Hardforks + EthereumHardforks,
305 Primitives = EthPrimitives,
306 Payload: EngineTypes<ExecutionData = ExecutionData>,
307 >,
308 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
309 >,
310 EthB: EthApiBuilder<N>,
311 PVB: Send,
312 EB: EngineApiBuilder<N>,
313 EVB: EngineValidatorBuilder<N>,
314 EthApiError: FromEvmError<N::Evm>,
315 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
316 RpcMiddleware: RethRpcMiddleware,
317 AuthHttpMiddleware: RethAuthHttpMiddleware<Identity>,
318{
319 type Handle = RpcHandle<N, EthB::EthApi>;
320
321 async fn launch_add_ons(
322 self,
323 ctx: reth_node_api::AddOnsContext<'_, N>,
324 ) -> eyre::Result<Self::Handle> {
325 let validation_api = ValidationApi::<_, _, <N::Types as NodeTypes>::Payload>::new(
326 ctx.node.provider().clone(),
327 Arc::new(ctx.node.consensus().clone()),
328 ctx.node.evm_config().clone(),
329 ctx.config.rpc.flashbots_config(),
330 ctx.node.task_executor().clone(),
331 Arc::new(EthereumEngineValidator::new(ctx.config.chain.clone())),
332 );
333
334 let eth_config =
335 EthConfigHandler::new(ctx.node.provider().clone(), ctx.node.evm_config().clone());
336
337 let testing_skip_invalid_transactions = ctx.config.rpc.testing_skip_invalid_transactions;
338 let testing_gas_limit_override = ctx.config.rpc.testing_gas_limit;
339
340 self.inner
341 .launch_add_ons_with(ctx, move |container| {
342 container.modules.merge_if_module_configured(
343 RethRpcModule::Flashbots,
344 validation_api.into_rpc(),
345 )?;
346
347 container
348 .modules
349 .merge_if_module_configured(RethRpcModule::Eth, eth_config.into_rpc())?;
350
351 let mut testing_api = TestingApi::new(
354 container.registry.eth_api().clone(),
355 container.registry.evm_config().clone(),
356 );
357 if testing_skip_invalid_transactions {
358 testing_api = testing_api.with_skip_invalid_transactions();
359 }
360 if let Some(gas_limit) = testing_gas_limit_override {
361 testing_api = testing_api.with_gas_limit_override(gas_limit);
362 }
363 container
364 .modules
365 .merge_if_module_configured(RethRpcModule::Testing, testing_api.into_rpc())?;
366
367 Ok(())
368 })
369 .await
370 }
371}
372
373impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> RethRpcAddOns<N>
374 for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
375where
376 N: FullNodeComponents<
377 Types: NodeTypes<
378 ChainSpec: Hardforks + EthereumHardforks,
379 Primitives = EthPrimitives,
380 Payload: EngineTypes<ExecutionData = ExecutionData>,
381 >,
382 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
383 >,
384 EthB: EthApiBuilder<N>,
385 PVB: PayloadValidatorBuilder<N>,
386 EB: EngineApiBuilder<N>,
387 EVB: EngineValidatorBuilder<N>,
388 EthApiError: FromEvmError<N::Evm>,
389 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
390 RpcMiddleware: RethRpcMiddleware,
391 AuthHttpMiddleware: RethAuthHttpMiddleware<Identity>,
392{
393 type EthApi = EthB::EthApi;
394
395 fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks<N, Self::EthApi> {
396 self.inner.hooks_mut()
397 }
398}
399
400impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> EngineValidatorAddOn<N>
401 for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
402where
403 N: FullNodeComponents<
404 Types: NodeTypes<
405 ChainSpec: EthChainSpec + EthereumHardforks,
406 Primitives = EthPrimitives,
407 Payload: EngineTypes<ExecutionData = ExecutionData>,
408 >,
409 Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
410 >,
411 EthB: EthApiBuilder<N>,
412 PVB: Send,
413 EB: EngineApiBuilder<N>,
414 EVB: EngineValidatorBuilder<N>,
415 EthApiError: FromEvmError<N::Evm>,
416 EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
417 RpcMiddleware: Send,
418 AuthHttpMiddleware: Send,
419{
420 type ValidatorBuilder = EVB;
421
422 fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
423 self.inner.engine_validator_builder()
424 }
425}
426
427impl<N> Node<N> for EthereumNode
428where
429 N: FullNodeTypes<Types = Self>,
430{
431 type ComponentsBuilder = ComponentsBuilder<
432 N,
433 EthereumPoolBuilder,
434 BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
435 EthereumNetworkBuilder,
436 EthereumExecutorBuilder,
437 EthereumConsensusBuilder,
438 >;
439
440 type AddOns =
441 EthereumAddOns<NodeAdapter<N>, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>;
442
443 fn components_builder(&self) -> Self::ComponentsBuilder {
444 Self::components()
445 }
446
447 fn add_ons(&self) -> Self::AddOns {
448 EthereumAddOns::default()
449 }
450}
451
452impl<N: FullNodeComponents<Types = Self>> DebugNode<N> for EthereumNode {
453 type RpcBlock = alloy_rpc_types_eth::Block;
454
455 fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> reth_ethereum_primitives::Block {
456 rpc_block.into_consensus().convert_transactions()
457 }
458
459 fn local_payload_attributes_builder(
460 chain_spec: &Self::ChainSpec,
461 ) -> impl PayloadAttributesBuilder<<Self::Payload as PayloadTypes>::PayloadAttributes> {
462 LocalPayloadAttributesBuilder::new(Arc::new(chain_spec.clone()))
463 }
464}
465
466#[derive(Debug, Default, Clone, Copy)]
468#[non_exhaustive]
469pub struct EthereumExecutorBuilder;
470
471impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
472where
473 Types: NodeTypes<
474 ChainSpec: Hardforks + EthExecutorSpec + EthereumHardforks,
475 Primitives = EthPrimitives,
476 >,
477 Node: FullNodeTypes<Types = Types>,
478{
479 type EVM = EthEvmConfig<Types::ChainSpec>;
480
481 async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
482 Ok(EthEvmConfig::new(ctx.chain_spec()))
483 }
484}
485
486#[derive(Debug, Default, Clone, Copy)]
491#[non_exhaustive]
492pub struct EthereumPoolBuilder {
493 }
495
496impl<Types, Node, Evm> PoolBuilder<Node, Evm> for EthereumPoolBuilder
497where
498 Types: NodeTypes<
499 ChainSpec: EthereumHardforks,
500 Primitives: NodePrimitives<SignedTx = TransactionSigned>,
501 >,
502 Node: FullNodeTypes<Types = Types>,
503 Evm: ConfigureEvm<Primitives = PrimitivesTy<Types>> + Clone + 'static,
504{
505 type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore, Evm>;
506
507 async fn build_pool(
508 self,
509 ctx: &BuilderContext<Node>,
510 evm_config: Evm,
511 ) -> eyre::Result<Self::Pool> {
512 let pool_config = ctx.pool_config();
513
514 let blobs_disabled = ctx.config().txpool.disable_blobs_support ||
515 ctx.config().txpool.blobpool_max_count == 0;
516
517 let blob_cache_size = if let Some(blob_cache_size) = pool_config.blob_cache_size {
518 Some(blob_cache_size)
519 } else {
520 let current_timestamp =
523 SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
524 let blob_params = ctx
525 .chain_spec()
526 .blob_params_at_timestamp(current_timestamp)
527 .unwrap_or_else(BlobParams::cancun);
528
529 Some((blob_params.target_blob_count * EPOCH_SLOTS * 2) as u32)
532 };
533
534 let blob_store =
535 reth_node_builder::components::create_blob_store_with_cache(ctx, blob_cache_size)?;
536
537 let validator =
538 TransactionValidationTaskExecutor::eth_builder(ctx.provider().clone(), evm_config)
539 .set_eip4844(!blobs_disabled)
540 .kzg_settings(ctx.kzg_settings()?)
541 .with_max_tx_input_bytes(ctx.config().txpool.max_tx_input_bytes)
542 .with_local_transactions_config(pool_config.local_transactions_config.clone())
543 .set_tx_fee_cap(ctx.config().rpc.rpc_tx_fee_cap)
544 .with_max_tx_gas_limit(ctx.config().txpool.max_tx_gas_limit)
545 .with_minimum_priority_fee(ctx.config().txpool.minimum_priority_fee)
546 .with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
547 .build_with_tasks(ctx.task_executor().clone(), blob_store.clone());
548
549 if validator.validator().eip4844() {
550 let kzg_settings = validator.validator().kzg_settings().clone();
554 ctx.task_executor().spawn_blocking_task(async move {
555 let _ = kzg_settings.get();
556 debug!(target: "reth::cli", "Initialized KZG settings");
557 });
558 }
559
560 let transaction_pool = TxPoolBuilder::new(ctx)
561 .with_validator(validator)
562 .build_and_spawn_maintenance_task(blob_store, pool_config)?;
563
564 info!(target: "reth::cli", "Transaction pool initialized");
565 debug!(target: "reth::cli", "Spawned txpool maintenance task");
566
567 Ok(transaction_pool)
568 }
569}
570
571#[derive(Debug, Default, Clone, Copy)]
573pub struct EthereumNetworkBuilder {
574 }
576
577impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetworkBuilder
578where
579 Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>,
580 Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
581 + Unpin
582 + 'static,
583{
584 type Network =
585 NetworkHandle<BasicNetworkPrimitives<PrimitivesTy<Node::Types>, PoolPooledTx<Pool>>>;
586
587 async fn build_network(
588 self,
589 ctx: &BuilderContext<Node>,
590 pool: Pool,
591 ) -> eyre::Result<Self::Network> {
592 let network = ctx.network_builder().await?;
593 let handle = ctx.start_network(network, pool);
594 info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
595 Ok(handle)
596 }
597}
598
599#[derive(Debug, Default, Clone, Copy)]
601pub struct EthereumConsensusBuilder {
602 }
604
605impl<Node> ConsensusBuilder<Node> for EthereumConsensusBuilder
606where
607 Node: FullNodeTypes<
608 Types: NodeTypes<ChainSpec: EthChainSpec + EthereumHardforks, Primitives = EthPrimitives>,
609 >,
610{
611 type Consensus = Arc<EthBeaconConsensus<<Node::Types as NodeTypes>::ChainSpec>>;
612
613 async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
614 Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
615 }
616}
617
618#[derive(Debug, Default, Clone)]
620#[non_exhaustive]
621pub struct EthereumEngineValidatorBuilder;
622
623impl<Node, Types> PayloadValidatorBuilder<Node> for EthereumEngineValidatorBuilder
624where
625 Types: NodeTypes<
626 ChainSpec: Hardforks + EthereumHardforks + Clone + 'static,
627 Payload: EngineTypes<ExecutionData = ExecutionData>
628 + PayloadTypes<PayloadAttributes = EthPayloadAttributes>,
629 Primitives = EthPrimitives,
630 >,
631 Node: FullNodeComponents<Types = Types>,
632{
633 type Validator = EthereumEngineValidator<Types::ChainSpec>;
634
635 async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
636 Ok(EthereumEngineValidator::new(ctx.config.chain.clone()))
637 }
638}