Skip to main content

reth_node_ethereum/
node.rs

1//! Ethereum Node types config.
2
3use crate::{EthEngineTypes, EthEvmConfig};
4use alloy_eips::{eip7840::BlobParams, merge::EPOCH_SLOTS};
5use alloy_network::Ethereum;
6use alloy_rpc_types_engine::ExecutionData;
7use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, Hardforks};
8use reth_engine_local::LocalPayloadAttributesBuilder;
9use reth_engine_primitives::EngineTypes;
10use reth_ethereum_consensus::EthBeaconConsensus;
11use reth_ethereum_engine_primitives::{EthBuiltPayload, EthPayloadAttributes};
12use reth_ethereum_primitives::{EthPrimitives, TransactionSigned};
13use reth_evm::{
14    eth::spec::EthExecutorSpec, ConfigureEvm, EvmFactory, EvmFactoryFor, NextBlockEnvAttributes,
15};
16use reth_evm_ethereum::factory::RethEvmFactory;
17#[cfg(feature = "jit")]
18use reth_evm_ethereum::factory::{JitBackend, JitMode, RevmcMetrics, RuntimeConfig, RuntimeTuning};
19use reth_network::{primitives::BasicNetworkPrimitives, NetworkHandle, PeersInfo};
20use reth_node_api::{
21    AddOnsContext, FullNodeComponents, HeaderTy, NodeAddOns, NodePrimitives,
22    PayloadAttributesBuilder, PrimitivesTy, TxTy,
23};
24use reth_node_builder::{
25    components::{
26        BasicPayloadServiceBuilder, ComponentsBuilder, ConsensusBuilder, ExecutorBuilder,
27        NetworkBuilder, PoolBuilder, TxPoolBuilder,
28    },
29    node::{FullNodeTypes, NodeTypes},
30    rpc::{
31        BasicEngineApiBuilder, BasicEngineValidatorBuilder, Either, EngineApiBuilder,
32        EngineValidatorAddOn, EngineValidatorBuilder, EthApiBuilder, EthApiCtx, Identity,
33        PayloadValidatorBuilder, RethAuthHttpMiddleware, RethRpcAddOns, RethRpcMiddleware,
34        RpcAddOns, RpcHandle, Stack,
35    },
36    BuilderContext, DebugNode, Node, NodeAdapter, PayloadBuilderConfig,
37};
38use reth_node_core::args::JitArgs;
39use reth_payload_primitives::PayloadTypes;
40use reth_provider::{providers::ProviderFactoryBuilder, EthStorage};
41use reth_rpc::{
42    eth::core::{EthApiFor, EthRpcConverterFor},
43    TestingApi, ValidationApi,
44};
45use reth_rpc_api::servers::{BlockSubmissionValidationApiServer, TestingApiServer};
46use reth_rpc_builder::config::RethRpcServerConfig;
47use reth_rpc_eth_api::{
48    helpers::{
49        config::{EthConfigApiServer, EthConfigHandler},
50        pending_block::BuildPendingEnv,
51    },
52    RpcConvert, RpcTypes, SignableTxRequest,
53};
54use reth_rpc_eth_types::{error::FromEvmError, EthApiError};
55use reth_rpc_server_types::RethRpcModule;
56use reth_tracing::tracing::{debug, info};
57use reth_transaction_pool::{
58    blobstore::DiskFileBlobStore, EthTransactionPool, PoolPooledTx, PoolTransaction,
59    TransactionPool, TransactionValidationTaskExecutor,
60};
61use revm::context::TxEnv;
62use std::{marker::PhantomData, sync::Arc, time::SystemTime};
63
64pub use crate::{payload::EthereumPayloadBuilder, EthereumEngineValidator};
65#[cfg(feature = "jit")]
66pub use reth_evm_ethereum::factory::maybe_run_jit_helper;
67
68/// Type configuration for a regular Ethereum node.
69#[derive(Debug, Default, Clone, Copy)]
70#[non_exhaustive]
71pub struct EthereumNode;
72
73impl EthereumNode {
74    /// Returns a [`ComponentsBuilder`] configured for a regular Ethereum node.
75    pub fn components<Node>() -> ComponentsBuilder<
76        Node,
77        EthereumPoolBuilder,
78        BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
79        EthereumNetworkBuilder,
80        EthereumExecutorBuilder,
81        EthereumConsensusBuilder,
82    >
83    where
84        Node: FullNodeTypes<
85            Types: NodeTypes<
86                ChainSpec: Hardforks + EthereumHardforks + EthExecutorSpec,
87                Primitives = EthPrimitives,
88            >,
89        >,
90        <Node::Types as NodeTypes>::Payload:
91            PayloadTypes<BuiltPayload = EthBuiltPayload, PayloadAttributes = EthPayloadAttributes>,
92    {
93        ComponentsBuilder::default()
94            .node_types::<Node>()
95            .pool(EthereumPoolBuilder::default())
96            .executor(EthereumExecutorBuilder::default())
97            .payload(BasicPayloadServiceBuilder::default())
98            .network(EthereumNetworkBuilder::default())
99            .consensus(EthereumConsensusBuilder::default())
100    }
101
102    /// Instantiates the [`ProviderFactoryBuilder`] for an ethereum node.
103    ///
104    /// # Open a Providerfactory in read-only mode from a datadir
105    ///
106    /// See also: [`ProviderFactoryBuilder`] and
107    /// [`ReadOnlyConfig`](reth_provider::providers::ReadOnlyConfig).
108    ///
109    /// ```no_run
110    /// use reth_chainspec::MAINNET;
111    /// use reth_node_ethereum::EthereumNode;
112    ///
113    /// fn demo(runtime: reth_tasks::Runtime) {
114    ///     let factory = EthereumNode::provider_factory_builder()
115    ///         .open_read_only(MAINNET.clone(), "datadir", runtime)
116    ///         .unwrap();
117    /// }
118    /// ```
119    ///
120    /// See also [`ProviderFactory::new`](reth_provider::ProviderFactory::new) for constructing
121    /// a [`ProviderFactory`](reth_provider::ProviderFactory) manually with all required
122    /// components.
123    pub fn provider_factory_builder() -> ProviderFactoryBuilder<Self> {
124        ProviderFactoryBuilder::default()
125    }
126}
127
128impl NodeTypes for EthereumNode {
129    type Primitives = EthPrimitives;
130    type ChainSpec = ChainSpec;
131    type Storage = EthStorage;
132    type Payload = EthEngineTypes;
133}
134
135/// Builds [`EthApi`](reth_rpc::EthApi) for Ethereum.
136#[derive(Debug)]
137pub struct EthereumEthApiBuilder<NetworkT = Ethereum>(PhantomData<NetworkT>);
138
139impl<NetworkT> Default for EthereumEthApiBuilder<NetworkT> {
140    fn default() -> Self {
141        Self(Default::default())
142    }
143}
144
145impl<N, NetworkT> EthApiBuilder<N> for EthereumEthApiBuilder<NetworkT>
146where
147    N: FullNodeComponents<
148        Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>,
149        Evm: ConfigureEvm<NextBlockEnvCtx: BuildPendingEnv<HeaderTy<N::Types>>>,
150    >,
151    NetworkT: RpcTypes<TransactionRequest: SignableTxRequest<TxTy<N::Types>>>,
152    EthRpcConverterFor<N, NetworkT>: RpcConvert<
153        Primitives = PrimitivesTy<N::Types>,
154        Error = EthApiError,
155        Network = NetworkT,
156        Evm = N::Evm,
157    >,
158    EthApiError: FromEvmError<N::Evm>,
159{
160    type EthApi = EthApiFor<N, NetworkT>;
161
162    async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
163        Ok(ctx.eth_api_builder().map_converter(|r| r.with_network()).build())
164    }
165}
166
167/// Add-ons w.r.t. l1 ethereum.
168#[derive(Debug)]
169pub struct EthereumAddOns<
170    N: FullNodeComponents,
171    EthB: EthApiBuilder<N>,
172    PVB,
173    EB = BasicEngineApiBuilder<PVB>,
174    EVB = BasicEngineValidatorBuilder<PVB>,
175    RpcMiddleware = Identity,
176    AuthHttpMiddleware = Identity,
177> {
178    inner: RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>,
179}
180
181impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
182    EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
183where
184    N: FullNodeComponents,
185    EthB: EthApiBuilder<N>,
186{
187    /// Creates a new instance from the inner `RpcAddOns`.
188    pub const fn new(
189        inner: RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>,
190    ) -> Self {
191        Self { inner }
192    }
193}
194
195impl<N> Default for EthereumAddOns<N, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>
196where
197    N: FullNodeComponents<
198        Types: NodeTypes<
199            ChainSpec: EthereumHardforks + Clone + 'static,
200            Payload: EngineTypes<ExecutionData = ExecutionData>
201                         + PayloadTypes<PayloadAttributes = EthPayloadAttributes>,
202            Primitives = EthPrimitives,
203        >,
204    >,
205    EthereumEthApiBuilder: EthApiBuilder<N>,
206{
207    fn default() -> Self {
208        Self::new(RpcAddOns::new(
209            EthereumEthApiBuilder::default(),
210            EthereumEngineValidatorBuilder::default(),
211            BasicEngineApiBuilder::default(),
212            BasicEngineValidatorBuilder::default(),
213            Default::default(),
214            Identity::new(),
215        ))
216    }
217}
218
219impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
220    EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
221where
222    N: FullNodeComponents,
223    EthB: EthApiBuilder<N>,
224{
225    /// Replace the engine API builder.
226    pub fn with_engine_api<T>(
227        self,
228        engine_api_builder: T,
229    ) -> EthereumAddOns<N, EthB, PVB, T, EVB, RpcMiddleware, AuthHttpMiddleware>
230    where
231        T: Send,
232    {
233        let Self { inner } = self;
234        EthereumAddOns::new(inner.with_engine_api(engine_api_builder))
235    }
236
237    /// Replace the payload validator builder.
238    pub fn with_payload_validator<V, T>(
239        self,
240        payload_validator_builder: T,
241    ) -> EthereumAddOns<N, EthB, T, EB, EVB, RpcMiddleware, AuthHttpMiddleware> {
242        let Self { inner } = self;
243        EthereumAddOns::new(inner.with_payload_validator(payload_validator_builder))
244    }
245
246    /// Sets rpc middleware
247    pub fn with_rpc_middleware<T>(
248        self,
249        rpc_middleware: T,
250    ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, T, AuthHttpMiddleware>
251    where
252        T: Send,
253    {
254        let Self { inner } = self;
255        EthereumAddOns::new(inner.with_rpc_middleware(rpc_middleware))
256    }
257
258    /// Configures the HTTP transport middleware for the auth / Engine API server.
259    pub fn with_auth_http_middleware<T>(
260        self,
261        auth_http_middleware: T,
262    ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, T>
263    where
264        T: Send,
265    {
266        let Self { inner } = self;
267        EthereumAddOns::new(inner.with_auth_http_middleware(auth_http_middleware))
268    }
269
270    /// Stacks an additional HTTP transport middleware layer for the auth / Engine API server.
271    pub fn layer_auth_http_middleware<T>(
272        self,
273        layer: T,
274    ) -> EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, Stack<AuthHttpMiddleware, T>> {
275        let Self { inner } = self;
276        EthereumAddOns::new(inner.layer_auth_http_middleware(layer))
277    }
278
279    /// Conditionally stacks an HTTP transport middleware layer for the auth / Engine API server.
280    #[expect(clippy::type_complexity)]
281    pub fn option_layer_auth_http_middleware<T>(
282        self,
283        layer: Option<T>,
284    ) -> EthereumAddOns<
285        N,
286        EthB,
287        PVB,
288        EB,
289        EVB,
290        RpcMiddleware,
291        Stack<AuthHttpMiddleware, Either<T, Identity>>,
292    > {
293        let Self { inner } = self;
294        EthereumAddOns::new(inner.option_layer_auth_http_middleware(layer))
295    }
296
297    /// Sets the tokio runtime for the RPC servers.
298    ///
299    /// Caution: This runtime must not be created from within asynchronous context.
300    pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
301        let Self { inner } = self;
302        Self { inner: inner.with_tokio_runtime(tokio_runtime) }
303    }
304}
305
306impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> NodeAddOns<N>
307    for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
308where
309    N: FullNodeComponents<
310        Types: NodeTypes<
311            ChainSpec: EthChainSpec + Hardforks + EthereumHardforks,
312            Primitives = EthPrimitives,
313            Payload: EngineTypes<ExecutionData = ExecutionData>,
314        >,
315        Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
316    >,
317    EthB: EthApiBuilder<N>,
318    PVB: Send,
319    EB: EngineApiBuilder<N>,
320    EVB: EngineValidatorBuilder<N>,
321    EthApiError: FromEvmError<N::Evm>,
322    EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
323    RpcMiddleware: RethRpcMiddleware,
324    AuthHttpMiddleware: RethAuthHttpMiddleware<Identity>,
325{
326    type Handle = RpcHandle<N, EthB::EthApi>;
327
328    async fn launch_add_ons(
329        self,
330        ctx: reth_node_api::AddOnsContext<'_, N>,
331    ) -> eyre::Result<Self::Handle> {
332        let validation_api = ValidationApi::<_, _, <N::Types as NodeTypes>::Payload>::new(
333            ctx.node.provider().clone(),
334            Arc::new(ctx.node.consensus().clone()),
335            ctx.node.evm_config().clone(),
336            ctx.config.rpc.flashbots_config(),
337            ctx.node.task_executor().clone(),
338            Arc::new(EthereumEngineValidator::new(ctx.config.chain.clone())),
339        );
340
341        let eth_config =
342            EthConfigHandler::new(ctx.node.provider().clone(), ctx.node.evm_config().clone());
343
344        let testing_skip_invalid_transactions = ctx.config.rpc.testing_skip_invalid_transactions;
345        let testing_gas_limit_override = ctx.config.rpc.testing_gas_limit;
346        let testing_desired_gas_limit = ctx.config.builder.gas_limit_for(ctx.config.chain.chain());
347        let testing_engine_handle = ctx.beacon_engine_handle.clone();
348
349        self.inner
350            .launch_add_ons_with(ctx, move |container| {
351                container.modules.merge_if_module_configured(
352                    RethRpcModule::Flashbots,
353                    validation_api.into_rpc(),
354                )?;
355
356                container
357                    .modules
358                    .merge_if_module_configured(RethRpcModule::Eth, eth_config.into_rpc())?;
359
360                // testing_buildBlockV1: only wire when the hidden testing module is explicitly
361                // requested on any transport. Default stays disabled to honor security guidance.
362                let mut testing_api = TestingApi::new(
363                    container.registry.eth_api().clone(),
364                    container.registry.evm_config().clone(),
365                    testing_desired_gas_limit,
366                    testing_engine_handle,
367                );
368                if testing_skip_invalid_transactions {
369                    testing_api = testing_api.with_skip_invalid_transactions();
370                }
371                if let Some(gas_limit) = testing_gas_limit_override {
372                    testing_api = testing_api.with_gas_limit_override(gas_limit);
373                }
374                container
375                    .modules
376                    .merge_if_module_configured(RethRpcModule::Testing, testing_api.into_rpc())?;
377
378                Ok(())
379            })
380            .await
381    }
382}
383
384impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> RethRpcAddOns<N>
385    for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
386where
387    N: FullNodeComponents<
388        Types: NodeTypes<
389            ChainSpec: Hardforks + EthereumHardforks,
390            Primitives = EthPrimitives,
391            Payload: EngineTypes<ExecutionData = ExecutionData>,
392        >,
393        Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
394    >,
395    EthB: EthApiBuilder<N>,
396    PVB: PayloadValidatorBuilder<N>,
397    EB: EngineApiBuilder<N>,
398    EVB: EngineValidatorBuilder<N>,
399    EthApiError: FromEvmError<N::Evm>,
400    EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
401    RpcMiddleware: RethRpcMiddleware,
402    AuthHttpMiddleware: RethAuthHttpMiddleware<Identity>,
403{
404    type EthApi = EthB::EthApi;
405
406    fn hooks_mut(&mut self) -> &mut reth_node_builder::rpc::RpcHooks<N, Self::EthApi> {
407        self.inner.hooks_mut()
408    }
409}
410
411impl<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware> EngineValidatorAddOn<N>
412    for EthereumAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware, AuthHttpMiddleware>
413where
414    N: FullNodeComponents<
415        Types: NodeTypes<
416            ChainSpec: EthChainSpec + EthereumHardforks,
417            Primitives = EthPrimitives,
418            Payload: EngineTypes<ExecutionData = ExecutionData>,
419        >,
420        Evm: ConfigureEvm<NextBlockEnvCtx = NextBlockEnvAttributes>,
421    >,
422    EthB: EthApiBuilder<N>,
423    PVB: Send,
424    EB: EngineApiBuilder<N>,
425    EVB: EngineValidatorBuilder<N>,
426    EthApiError: FromEvmError<N::Evm>,
427    EvmFactoryFor<N::Evm>: EvmFactory<Tx = TxEnv>,
428    RpcMiddleware: Send,
429    AuthHttpMiddleware: Send,
430{
431    type ValidatorBuilder = EVB;
432
433    fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
434        self.inner.engine_validator_builder()
435    }
436}
437
438impl<N> Node<N> for EthereumNode
439where
440    N: FullNodeTypes<Types = Self>,
441{
442    type ComponentsBuilder = ComponentsBuilder<
443        N,
444        EthereumPoolBuilder,
445        BasicPayloadServiceBuilder<EthereumPayloadBuilder>,
446        EthereumNetworkBuilder,
447        EthereumExecutorBuilder,
448        EthereumConsensusBuilder,
449    >;
450
451    type AddOns =
452        EthereumAddOns<NodeAdapter<N>, EthereumEthApiBuilder, EthereumEngineValidatorBuilder>;
453
454    fn components_builder(&self) -> Self::ComponentsBuilder {
455        Self::components()
456    }
457
458    fn add_ons(&self) -> Self::AddOns {
459        EthereumAddOns::default()
460    }
461}
462
463impl<N: FullNodeComponents<Types = Self>> DebugNode<N> for EthereumNode {
464    type RpcBlock = alloy_rpc_types_eth::Block;
465
466    fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> reth_ethereum_primitives::Block {
467        rpc_block.into_consensus().convert_transactions()
468    }
469
470    fn local_payload_attributes_builder(
471        chain_spec: &Self::ChainSpec,
472    ) -> impl PayloadAttributesBuilder<<Self::Payload as PayloadTypes>::PayloadAttributes> {
473        LocalPayloadAttributesBuilder::new(Arc::new(chain_spec.clone()))
474    }
475}
476
477/// Builds a [`RuntimeConfig`] from CLI [`JitArgs`].
478#[cfg(feature = "jit")]
479fn jit_runtime_config(jit: &JitArgs) -> RuntimeConfig {
480    let default_tuning = RuntimeTuning::default();
481    let tuning = RuntimeTuning {
482        channel_capacity: jit.channel_capacity,
483        jit_hot_threshold: jit.hot_threshold,
484        jit_max_bytecode_len: jit.max_bytecode_len,
485        jit_max_pending_jobs: jit.max_pending_jobs,
486        jit_worker_count: jit.worker_count.unwrap_or(default_tuning.jit_worker_count),
487        jit_timeout: default_tuning.jit_timeout,
488        jit_helper_memory_limit_bytes: default_tuning.jit_helper_memory_limit_bytes,
489        jit_helper_cpu_count: default_tuning.jit_helper_cpu_count,
490        resident_code_cache_bytes: jit.code_cache_bytes,
491        idle_evict_duration: Some(jit.idle_evict_duration),
492
493        max_events_per_drain: default_tuning.max_events_per_drain,
494        event_drain_interval: default_tuning.event_drain_interval,
495        shutdown_timeout: default_tuning.shutdown_timeout,
496        jit_worker_queue_capacity: default_tuning.jit_worker_queue_capacity,
497        jit_opt_level: default_tuning.jit_opt_level,
498        aot_opt_level: default_tuning.aot_opt_level,
499        eviction_sweep_interval: default_tuning.eviction_sweep_interval,
500        compiler_recycle_threshold: default_tuning.compiler_recycle_threshold,
501    };
502
503    let default_config = RuntimeConfig::default();
504    RuntimeConfig {
505        enabled: jit.enabled,
506        thread_name: default_config.thread_name,
507        store: default_config.store,
508        tuning,
509        dump_dir: default_config.dump_dir,
510        debug_assertions: jit.debug,
511        blocking: jit.blocking,
512        no_dedup: default_config.no_dedup,
513        no_dse: default_config.no_dse,
514        gas_params: default_config.gas_params,
515        aot: default_config.aot,
516        jit_mode: JitMode::OutOfProcess,
517        jit_helper_path: default_config.jit_helper_path,
518        on_compilation: default_config.on_compilation,
519    }
520}
521
522/// Builds an [`EthEvmConfig`] with revmc JIT from CLI [`JitArgs`].
523///
524/// This is the shared setup used by both [`EthereumExecutorBuilder`] and `reth re-execute`.
525///
526/// Returns the evm config and metrics recorder if JIT starts enabled.
527#[cfg(feature = "jit")]
528#[allow(clippy::type_complexity)]
529pub fn build_evm_config<C: EthereumHardforks>(
530    chain_spec: Arc<C>,
531    jit: &JitArgs,
532    dump_dir: Option<std::path::PathBuf>,
533) -> eyre::Result<(EthEvmConfig<C, RethEvmFactory>, Option<Arc<RevmcMetrics>>)> {
534    if !jit.enabled {
535        let factory = RethEvmFactory::disabled();
536        return Ok((EthEvmConfig::new_with_evm_factory(chain_spec, factory), None));
537    }
538
539    let mut config = jit_runtime_config(jit);
540    config.dump_dir = dump_dir;
541
542    let revmc_metrics = Arc::new(RevmcMetrics::default());
543    let compilation_metrics = revmc_metrics.clone();
544    config.on_compilation = Some(Arc::new(move |event| {
545        compilation_metrics.record_compilation(&event);
546    }));
547
548    let tuning = config.tuning;
549    let jit_mode = config.jit_mode;
550    let backend = JitBackend::new(config)?;
551
552    reth_tracing::tracing::warn!(target: "reth::cli",
553        hot_threshold = tuning.jit_hot_threshold,
554        workers = tuning.jit_worker_count,
555        mode = ?jit_mode,
556        blocking = jit.blocking,
557        "Started experimental revmc JIT backend; this may cause instability",
558    );
559
560    let factory = RethEvmFactory::new_with_metrics(backend, revmc_metrics.as_ref().clone());
561    let evm_config = EthEvmConfig::new_with_evm_factory(chain_spec, factory);
562
563    Ok((evm_config, Some(revmc_metrics)))
564}
565
566/// Builds an [`EthEvmConfig`] from CLI [`JitArgs`].
567///
568/// This is the shared setup used by both [`EthereumExecutorBuilder`] and `reth re-execute`.
569///
570/// Compiled without the `jit` feature: errors if JIT was requested via [`JitArgs`] and otherwise
571/// returns a plain interpreter-backed config.
572#[cfg(not(feature = "jit"))]
573#[allow(clippy::type_complexity)]
574pub fn build_evm_config<C: EthereumHardforks>(
575    chain_spec: Arc<C>,
576    jit: &JitArgs,
577    _dump_dir: Option<std::path::PathBuf>,
578) -> eyre::Result<(EthEvmConfig<C, RethEvmFactory>, Option<()>)> {
579    if jit.enabled {
580        eyre::bail!(
581            "JIT compilation was requested but this binary was compiled without the `jit` feature"
582        );
583    }
584    let factory = RethEvmFactory::default();
585    Ok((EthEvmConfig::new_with_evm_factory(chain_spec, factory), None))
586}
587
588/// A regular ethereum evm and executor builder.
589///
590/// Uses [`RethEvmFactory`].
591#[derive(Debug, Default, Clone, Copy)]
592#[non_exhaustive]
593pub struct EthereumExecutorBuilder;
594
595impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
596where
597    Types: NodeTypes<
598        ChainSpec: Hardforks + EthExecutorSpec + EthereumHardforks,
599        Primitives = EthPrimitives,
600    >,
601    Node: FullNodeTypes<Types = Types>,
602{
603    type EVM = EthEvmConfig<Types::ChainSpec, RethEvmFactory>;
604
605    async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
606        let jit = &ctx.config().jit;
607        let dump_dir = jit.debug.then(|| ctx.config().datadir().data_dir().join("jit"));
608
609        let (evm_config, revmc_metrics) = build_evm_config(ctx.chain_spec(), jit, dump_dir)?;
610
611        #[cfg(not(feature = "jit"))]
612        let _ = revmc_metrics;
613
614        #[cfg(feature = "jit")]
615        if let Some(revmc_metrics) = revmc_metrics {
616            let metrics_backend = evm_config.executor_factory.evm_factory().backend().clone();
617            ctx.task_executor().spawn_with_graceful_shutdown_signal(|shutdown| async move {
618                let mut shutdown = std::pin::pin!(shutdown);
619                loop {
620                    tokio::select! {
621                        _ = tokio::time::sleep(std::time::Duration::from_secs(5)) => {
622                            revmc_metrics.record(&metrics_backend.stats());
623                        }
624                        _ = &mut shutdown => break,
625                    }
626                }
627            });
628        }
629
630        Ok(evm_config)
631    }
632}
633
634/// A basic ethereum transaction pool.
635///
636/// This contains various settings that can be configured and take precedence over the node's
637/// config.
638#[derive(Debug, Default, Clone, Copy)]
639#[non_exhaustive]
640pub struct EthereumPoolBuilder {
641    // TODO add options for txpool args
642}
643
644impl<Types, Node, Evm> PoolBuilder<Node, Evm> for EthereumPoolBuilder
645where
646    Types: NodeTypes<
647        ChainSpec: EthereumHardforks,
648        Primitives: NodePrimitives<SignedTx = TransactionSigned>,
649    >,
650    Node: FullNodeTypes<Types = Types>,
651    Evm: ConfigureEvm<Primitives = PrimitivesTy<Types>> + Clone + 'static,
652{
653    type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore, Evm>;
654
655    async fn build_pool(
656        self,
657        ctx: &BuilderContext<Node>,
658        evm_config: Evm,
659    ) -> eyre::Result<Self::Pool> {
660        let pool_config = ctx.pool_config();
661
662        let blobs_disabled = ctx.config().txpool.disable_blobs_support ||
663            ctx.config().txpool.blobpool_max_count == 0;
664
665        let blob_cache_size = if let Some(blob_cache_size) = pool_config.blob_cache_size {
666            Some(blob_cache_size)
667        } else {
668            // get the current blob params for the current timestamp, fallback to default Cancun
669            // params
670            let current_timestamp =
671                SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_secs();
672            let blob_params = ctx
673                .chain_spec()
674                .blob_params_at_timestamp(current_timestamp)
675                .unwrap_or_else(BlobParams::cancun);
676
677            // Derive the blob cache size from the target blob count, to auto scale it by
678            // multiplying it with the slot count for 2 epochs: 384 for pectra
679            Some((blob_params.target_blob_count * EPOCH_SLOTS * 2) as u32)
680        };
681
682        let blob_store =
683            reth_node_builder::components::create_blob_store_with_cache(ctx, blob_cache_size)?;
684
685        let validator =
686            TransactionValidationTaskExecutor::eth_builder(ctx.provider().clone(), evm_config)
687                .set_eip4844(!blobs_disabled)
688                .kzg_settings(ctx.kzg_settings()?)
689                .with_max_tx_input_bytes(ctx.config().txpool.max_tx_input_bytes)
690                .with_local_transactions_config(pool_config.local_transactions_config.clone())
691                .set_tx_fee_cap(ctx.config().rpc.rpc_tx_fee_cap)
692                .with_max_tx_gas_limit(ctx.config().txpool.max_tx_gas_limit)
693                .with_minimum_priority_fee(ctx.config().txpool.minimum_priority_fee)
694                .with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
695                .build_with_tasks(ctx.task_executor().clone(), blob_store.clone());
696
697        if validator.validator().eip4844() {
698            // initializing the KZG settings can be expensive, this should be done upfront so that
699            // it doesn't impact the first block or the first gossiped blob transaction, so we
700            // initialize this in the background
701            let kzg_settings = validator.validator().kzg_settings().clone();
702            ctx.task_executor().spawn_blocking_task(async move {
703                let _ = kzg_settings.get();
704                debug!(target: "reth::cli", "Initialized KZG settings");
705            });
706        }
707
708        let transaction_pool = TxPoolBuilder::new(ctx)
709            .with_validator(validator)
710            .build_and_spawn_maintenance_task(blob_store, pool_config)?;
711
712        info!(target: "reth::cli", "Transaction pool initialized");
713        debug!(target: "reth::cli", "Spawned txpool maintenance task");
714
715        Ok(transaction_pool)
716    }
717}
718
719/// A basic ethereum payload service.
720#[derive(Debug, Default, Clone, Copy)]
721pub struct EthereumNetworkBuilder {
722    // TODO add closure to modify network
723}
724
725impl<Node, Pool> NetworkBuilder<Node, Pool> for EthereumNetworkBuilder
726where
727    Node: FullNodeTypes<Types: NodeTypes<ChainSpec: Hardforks>>,
728    Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
729        + Unpin
730        + 'static,
731{
732    type Network =
733        NetworkHandle<BasicNetworkPrimitives<PrimitivesTy<Node::Types>, PoolPooledTx<Pool>>>;
734
735    async fn build_network(
736        self,
737        ctx: &BuilderContext<Node>,
738        pool: Pool,
739    ) -> eyre::Result<Self::Network> {
740        let network = ctx.network_builder().await?;
741        let handle = ctx.start_network(network, pool);
742        info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
743        Ok(handle)
744    }
745}
746
747/// A basic ethereum consensus builder.
748#[derive(Debug, Default, Clone, Copy)]
749pub struct EthereumConsensusBuilder {
750    // TODO add closure to modify consensus
751}
752
753impl<Node> ConsensusBuilder<Node> for EthereumConsensusBuilder
754where
755    Node: FullNodeTypes<
756        Types: NodeTypes<ChainSpec: EthChainSpec + EthereumHardforks, Primitives = EthPrimitives>,
757    >,
758{
759    type Consensus = Arc<EthBeaconConsensus<<Node::Types as NodeTypes>::ChainSpec>>;
760
761    async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
762        Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
763    }
764}
765
766/// Builder for [`EthereumEngineValidator`].
767#[derive(Debug, Default, Clone)]
768#[non_exhaustive]
769pub struct EthereumEngineValidatorBuilder;
770
771impl<Node, Types> PayloadValidatorBuilder<Node> for EthereumEngineValidatorBuilder
772where
773    Types: NodeTypes<
774        ChainSpec: Hardforks + EthereumHardforks + Clone + 'static,
775        Payload: EngineTypes<ExecutionData = ExecutionData>
776                     + PayloadTypes<PayloadAttributes = EthPayloadAttributes>,
777        Primitives = EthPrimitives,
778    >,
779    Node: FullNodeComponents<Types = Types>,
780{
781    type Validator = EthereumEngineValidator<Types::ChainSpec>;
782
783    async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
784        Ok(EthereumEngineValidator::new(ctx.config.chain.clone()))
785    }
786}