reth_node_builder/
rpc.rs

1//! Builder support for rpc components.
2
3pub use jsonrpsee::server::middleware::rpc::{RpcService, RpcServiceBuilder};
4pub use reth_engine_tree::tree::{BasicEngineValidator, EngineValidator};
5pub use reth_rpc_builder::{middleware::RethRpcMiddleware, Identity, Stack};
6
7use crate::{
8    invalid_block_hook::InvalidBlockHookExt, ConfigureEngineEvm, ConsensusEngineEvent,
9    ConsensusEngineHandle,
10};
11use alloy_rpc_types::engine::ClientVersionV1;
12use alloy_rpc_types_engine::ExecutionData;
13use jsonrpsee::{core::middleware::layer::Either, RpcModule};
14use reth_chain_state::CanonStateSubscriptions;
15use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks, Hardforks};
16use reth_node_api::{
17    AddOnsContext, BlockTy, EngineApiValidator, EngineTypes, FullNodeComponents, FullNodeTypes,
18    NodeAddOns, NodeTypes, PayloadTypes, PayloadValidator, PrimitivesTy, TreeConfig,
19};
20use reth_node_core::{
21    cli::config::RethTransactionPoolConfig,
22    node_config::NodeConfig,
23    version::{version_metadata, CLIENT_CODE},
24};
25use reth_payload_builder::{PayloadBuilderHandle, PayloadStore};
26use reth_rpc::eth::{core::EthRpcConverterFor, EthApiTypes, FullEthApiServer};
27use reth_rpc_api::{eth::helpers::AddDevSigners, IntoEngineApiRpcModule};
28use reth_rpc_builder::{
29    auth::{AuthRpcModule, AuthServerHandle},
30    config::RethRpcServerConfig,
31    RpcModuleBuilder, RpcRegistryInner, RpcServerConfig, RpcServerHandle, TransportRpcModules,
32};
33use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
34use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
35use reth_tokio_util::EventSender;
36use reth_tracing::tracing::{debug, info};
37use std::{
38    fmt::{self, Debug},
39    future::Future,
40    ops::{Deref, DerefMut},
41};
42
43/// Contains the handles to the spawned RPC servers.
44///
45/// This can be used to access the endpoints of the servers.
46#[derive(Debug, Clone)]
47pub struct RethRpcServerHandles {
48    /// The regular RPC server handle to all configured transports.
49    pub rpc: RpcServerHandle,
50    /// The handle to the auth server (engine API)
51    pub auth: AuthServerHandle,
52}
53
54/// Contains hooks that are called during the rpc setup.
55pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
56    /// Hooks to run once RPC server is running.
57    pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
58    /// Hooks to run to configure RPC server API.
59    pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
60}
61
62impl<Node, EthApi> Default for RpcHooks<Node, EthApi>
63where
64    Node: FullNodeComponents,
65    EthApi: EthApiTypes,
66{
67    fn default() -> Self {
68        Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
69    }
70}
71
72impl<Node, EthApi> RpcHooks<Node, EthApi>
73where
74    Node: FullNodeComponents,
75    EthApi: EthApiTypes,
76{
77    /// Sets the hook that is run once the rpc server is started.
78    pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
79    where
80        F: OnRpcStarted<Node, EthApi> + 'static,
81    {
82        self.on_rpc_started = Box::new(hook);
83        self
84    }
85
86    /// Sets the hook that is run once the rpc server is started.
87    #[expect(unused)]
88    pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
89    where
90        F: OnRpcStarted<Node, EthApi> + 'static,
91    {
92        self.set_on_rpc_started(hook);
93        self
94    }
95
96    /// Sets the hook that is run to configure the rpc modules.
97    pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
98    where
99        F: ExtendRpcModules<Node, EthApi> + 'static,
100    {
101        self.extend_rpc_modules = Box::new(hook);
102        self
103    }
104
105    /// Sets the hook that is run to configure the rpc modules.
106    #[expect(unused)]
107    pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
108    where
109        F: ExtendRpcModules<Node, EthApi> + 'static,
110    {
111        self.set_extend_rpc_modules(hook);
112        self
113    }
114}
115
116impl<Node, EthApi> fmt::Debug for RpcHooks<Node, EthApi>
117where
118    Node: FullNodeComponents,
119    EthApi: EthApiTypes,
120{
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.debug_struct("RpcHooks")
123            .field("on_rpc_started", &"...")
124            .field("extend_rpc_modules", &"...")
125            .finish()
126    }
127}
128
129/// Event hook that is called once the rpc server is started.
130pub trait OnRpcStarted<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
131    /// The hook that is called once the rpc server is started.
132    fn on_rpc_started(
133        self: Box<Self>,
134        ctx: RpcContext<'_, Node, EthApi>,
135        handles: RethRpcServerHandles,
136    ) -> eyre::Result<()>;
137}
138
139impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
140where
141    F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
142    Node: FullNodeComponents,
143    EthApi: EthApiTypes,
144{
145    fn on_rpc_started(
146        self: Box<Self>,
147        ctx: RpcContext<'_, Node, EthApi>,
148        handles: RethRpcServerHandles,
149    ) -> eyre::Result<()> {
150        (*self)(ctx, handles)
151    }
152}
153
154impl<Node, EthApi> OnRpcStarted<Node, EthApi> for ()
155where
156    Node: FullNodeComponents,
157    EthApi: EthApiTypes,
158{
159    fn on_rpc_started(
160        self: Box<Self>,
161        _: RpcContext<'_, Node, EthApi>,
162        _: RethRpcServerHandles,
163    ) -> eyre::Result<()> {
164        Ok(())
165    }
166}
167
168/// Event hook that is called when the rpc server is started.
169pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
170    /// The hook that is called once the rpc server is started.
171    fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
172}
173
174impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
175where
176    F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
177    Node: FullNodeComponents,
178    EthApi: EthApiTypes,
179{
180    fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
181        (*self)(ctx)
182    }
183}
184
185impl<Node, EthApi> ExtendRpcModules<Node, EthApi> for ()
186where
187    Node: FullNodeComponents,
188    EthApi: EthApiTypes,
189{
190    fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
191        Ok(())
192    }
193}
194
195/// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait.
196#[derive(Debug, Clone)]
197#[expect(clippy::type_complexity)]
198pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
199    pub(crate) registry: RpcRegistryInner<
200        Node::Provider,
201        Node::Pool,
202        Node::Network,
203        EthApi,
204        Node::Evm,
205        Node::Consensus,
206    >,
207}
208
209impl<Node, EthApi> Deref for RpcRegistry<Node, EthApi>
210where
211    Node: FullNodeComponents,
212    EthApi: EthApiTypes,
213{
214    type Target = RpcRegistryInner<
215        Node::Provider,
216        Node::Pool,
217        Node::Network,
218        EthApi,
219        Node::Evm,
220        Node::Consensus,
221    >;
222
223    fn deref(&self) -> &Self::Target {
224        &self.registry
225    }
226}
227
228impl<Node, EthApi> DerefMut for RpcRegistry<Node, EthApi>
229where
230    Node: FullNodeComponents,
231    EthApi: EthApiTypes,
232{
233    fn deref_mut(&mut self) -> &mut Self::Target {
234        &mut self.registry
235    }
236}
237
238/// Helper container for the parameters commonly passed to RPC module extension functions.
239#[expect(missing_debug_implementations)]
240pub struct RpcModuleContainer<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
241    /// Holds installed modules per transport type.
242    pub modules: &'a mut TransportRpcModules,
243    /// Holds jwt authenticated rpc module.
244    pub auth_module: &'a mut AuthRpcModule,
245    /// A Helper type the holds instances of the configured modules.
246    pub registry: &'a mut RpcRegistry<Node, EthApi>,
247}
248
249/// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and
250/// [`AuthRpcModule`].
251///
252/// This can be used to access installed modules, or create commonly used handlers like
253/// [`reth_rpc::eth::EthApi`], and ultimately merge additional rpc handler into the configured
254/// transport modules [`TransportRpcModules`] as well as configured authenticated methods
255/// [`AuthRpcModule`].
256#[expect(missing_debug_implementations)]
257pub struct RpcContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
258    /// The node components.
259    pub(crate) node: Node,
260
261    /// Gives access to the node configuration.
262    pub(crate) config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
263
264    /// A Helper type the holds instances of the configured modules.
265    ///
266    /// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`].
267    pub registry: &'a mut RpcRegistry<Node, EthApi>,
268    /// Holds installed modules per transport type.
269    ///
270    /// This can be used to merge additional modules into the configured transports (http, ipc,
271    /// ws). See [`TransportRpcModules::merge_configured`]
272    pub modules: &'a mut TransportRpcModules,
273    /// Holds jwt authenticated rpc module.
274    ///
275    /// This can be used to merge additional modules into the configured authenticated methods
276    pub auth_module: &'a mut AuthRpcModule,
277}
278
279impl<Node, EthApi> RpcContext<'_, Node, EthApi>
280where
281    Node: FullNodeComponents,
282    EthApi: EthApiTypes,
283{
284    /// Returns the config of the node.
285    pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
286        self.config
287    }
288
289    /// Returns a reference to the configured node.
290    ///
291    /// This gives access to the node's components.
292    pub const fn node(&self) -> &Node {
293        &self.node
294    }
295
296    /// Returns the transaction pool instance.
297    pub fn pool(&self) -> &Node::Pool {
298        self.node.pool()
299    }
300
301    /// Returns provider to interact with the node.
302    pub fn provider(&self) -> &Node::Provider {
303        self.node.provider()
304    }
305
306    /// Returns the handle to the network
307    pub fn network(&self) -> &Node::Network {
308        self.node.network()
309    }
310
311    /// Returns the handle to the payload builder service
312    pub fn payload_builder_handle(
313        &self,
314    ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
315        self.node.payload_builder_handle()
316    }
317}
318
319/// Handle to the launched RPC servers.
320pub struct RpcHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
321    /// Handles to launched servers.
322    pub rpc_server_handles: RethRpcServerHandles,
323    /// Configured RPC modules.
324    pub rpc_registry: RpcRegistry<Node, EthApi>,
325    /// Notification channel for engine API events
326    ///
327    /// Caution: This is a multi-producer, multi-consumer broadcast and allows grants access to
328    /// dispatch events
329    pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
330    /// Handle to the beacon consensus engine.
331    pub beacon_engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
332}
333
334impl<Node: FullNodeComponents, EthApi: EthApiTypes> Clone for RpcHandle<Node, EthApi> {
335    fn clone(&self) -> Self {
336        Self {
337            rpc_server_handles: self.rpc_server_handles.clone(),
338            rpc_registry: self.rpc_registry.clone(),
339            engine_events: self.engine_events.clone(),
340            beacon_engine_handle: self.beacon_engine_handle.clone(),
341        }
342    }
343}
344
345impl<Node: FullNodeComponents, EthApi: EthApiTypes> Deref for RpcHandle<Node, EthApi> {
346    type Target = RpcRegistry<Node, EthApi>;
347
348    fn deref(&self) -> &Self::Target {
349        &self.rpc_registry
350    }
351}
352
353impl<Node: FullNodeComponents, EthApi: EthApiTypes> Debug for RpcHandle<Node, EthApi>
354where
355    RpcRegistry<Node, EthApi>: Debug,
356{
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        f.debug_struct("RpcHandle")
359            .field("rpc_server_handles", &self.rpc_server_handles)
360            .field("rpc_registry", &self.rpc_registry)
361            .finish()
362    }
363}
364
365impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcHandle<Node, EthApi> {
366    /// Returns the RPC server handles.
367    pub const fn rpc_server_handles(&self) -> &RethRpcServerHandles {
368        &self.rpc_server_handles
369    }
370
371    /// Returns the consensus engine handle.
372    ///
373    /// This handle can be used to interact with the engine service directly.
374    pub const fn consensus_engine_handle(
375        &self,
376    ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
377        &self.beacon_engine_handle
378    }
379
380    /// Returns the consensus engine events sender.
381    pub const fn consensus_engine_events(
382        &self,
383    ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
384        &self.engine_events
385    }
386}
387
388/// Handle returned when only the regular RPC server (HTTP/WS/IPC) is launched.
389///
390/// This handle provides access to the RPC server endpoints and registry, but does not
391/// include an authenticated Engine API server. Use this when you only need regular
392/// RPC functionality.
393#[derive(Debug, Clone)]
394pub struct RpcServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
395    /// Handle to the RPC server
396    pub rpc_server_handle: RpcServerHandle,
397    /// Configured RPC modules.
398    pub rpc_registry: RpcRegistry<Node, EthApi>,
399    /// Notification channel for engine API events
400    pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
401    /// Handle to the consensus engine.
402    pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
403}
404
405impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcServerOnlyHandle<Node, EthApi> {
406    /// Returns the RPC server handle.
407    pub const fn rpc_server_handle(&self) -> &RpcServerHandle {
408        &self.rpc_server_handle
409    }
410
411    /// Returns the consensus engine handle.
412    ///
413    /// This handle can be used to interact with the engine service directly.
414    pub const fn consensus_engine_handle(
415        &self,
416    ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
417        &self.engine_handle
418    }
419
420    /// Returns the consensus engine events sender.
421    pub const fn consensus_engine_events(
422        &self,
423    ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
424        &self.engine_events
425    }
426}
427
428/// Handle returned when only the authenticated Engine API server is launched.
429///
430/// This handle provides access to the Engine API server and registry, but does not
431/// include the regular RPC servers (HTTP/WS/IPC). Use this for specialized setups
432/// that only need Engine API functionality.
433#[derive(Debug, Clone)]
434pub struct AuthServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
435    /// Handle to the auth server (engine API)
436    pub auth_server_handle: AuthServerHandle,
437    /// Configured RPC modules.
438    pub rpc_registry: RpcRegistry<Node, EthApi>,
439    /// Notification channel for engine API events
440    pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
441    /// Handle to the consensus engine.
442    pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
443}
444
445impl<Node: FullNodeComponents, EthApi: EthApiTypes> AuthServerOnlyHandle<Node, EthApi> {
446    /// Returns the consensus engine handle.
447    ///
448    /// This handle can be used to interact with the engine service directly.
449    pub const fn consensus_engine_handle(
450        &self,
451    ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
452        &self.engine_handle
453    }
454
455    /// Returns the consensus engine events sender.
456    pub const fn consensus_engine_events(
457        &self,
458    ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
459        &self.engine_events
460    }
461}
462
463/// Internal context struct for RPC setup shared between different launch methods
464struct RpcSetupContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
465    node: Node,
466    config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
467    modules: TransportRpcModules,
468    auth_module: AuthRpcModule,
469    auth_config: reth_rpc_builder::auth::AuthServerConfig,
470    registry: RpcRegistry<Node, EthApi>,
471    on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
472    engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
473    engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
474}
475
476/// Node add-ons containing RPC server configuration, with customizable eth API handler.
477///
478/// This struct can be used to provide the RPC server functionality. It is responsible for launching
479/// the regular RPC and the authenticated RPC server (engine API). It is intended to be used and
480/// modified as part of the [`NodeAddOns`] see for example `OpRpcAddons`, `EthereumAddOns`.
481///
482/// It can be modified to register RPC API handlers, see [`RpcAddOns::launch_add_ons_with`] which
483/// takes a closure that provides access to all the configured modules (namespaces), and is invoked
484/// just before the servers are launched. This can be used to extend the node with custom RPC
485/// methods or even replace existing method handlers, see also [`TransportRpcModules`].
486pub struct RpcAddOns<
487    Node: FullNodeComponents,
488    EthB: EthApiBuilder<Node>,
489    PVB,
490    EB = BasicEngineApiBuilder<PVB>,
491    EVB = BasicEngineValidatorBuilder<PVB>,
492    RpcMiddleware = Identity,
493> {
494    /// Additional RPC add-ons.
495    pub hooks: RpcHooks<Node, EthB::EthApi>,
496    /// Builder for `EthApi`
497    eth_api_builder: EthB,
498    /// Payload validator builder
499    payload_validator_builder: PVB,
500    /// Builder for `EngineApi`
501    engine_api_builder: EB,
502    /// Builder for tree validator
503    engine_validator_builder: EVB,
504    /// Configurable RPC middleware stack.
505    ///
506    /// This middleware is applied to all RPC requests across all transports (HTTP, WS, IPC).
507    /// See [`RpcAddOns::with_rpc_middleware`] for more details.
508    rpc_middleware: RpcMiddleware,
509    /// Optional custom tokio runtime for the RPC server.
510    tokio_runtime: Option<tokio::runtime::Handle>,
511}
512
513impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> Debug
514    for RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
515where
516    Node: FullNodeComponents,
517    EthB: EthApiBuilder<Node>,
518    PVB: Debug,
519    EB: Debug,
520    EVB: Debug,
521{
522    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523        f.debug_struct("RpcAddOns")
524            .field("hooks", &self.hooks)
525            .field("eth_api_builder", &"...")
526            .field("payload_validator_builder", &self.payload_validator_builder)
527            .field("engine_api_builder", &self.engine_api_builder)
528            .field("engine_validator_builder", &self.engine_validator_builder)
529            .field("rpc_middleware", &"...")
530            .finish()
531    }
532}
533
534impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
535where
536    Node: FullNodeComponents,
537    EthB: EthApiBuilder<Node>,
538{
539    /// Creates a new instance of the RPC add-ons.
540    pub fn new(
541        eth_api_builder: EthB,
542        payload_validator_builder: PVB,
543        engine_api_builder: EB,
544        engine_validator_builder: EVB,
545        rpc_middleware: RpcMiddleware,
546    ) -> Self {
547        Self {
548            hooks: RpcHooks::default(),
549            eth_api_builder,
550            payload_validator_builder,
551            engine_api_builder,
552            engine_validator_builder,
553            rpc_middleware,
554            tokio_runtime: None,
555        }
556    }
557
558    /// Maps the [`EngineApiBuilder`] builder type.
559    pub fn with_engine_api<T>(
560        self,
561        engine_api_builder: T,
562    ) -> RpcAddOns<Node, EthB, PVB, T, EVB, RpcMiddleware> {
563        let Self {
564            hooks,
565            eth_api_builder,
566            payload_validator_builder,
567            engine_validator_builder,
568            rpc_middleware,
569            tokio_runtime,
570            ..
571        } = self;
572        RpcAddOns {
573            hooks,
574            eth_api_builder,
575            payload_validator_builder,
576            engine_api_builder,
577            engine_validator_builder,
578            rpc_middleware,
579            tokio_runtime,
580        }
581    }
582
583    /// Maps the [`PayloadValidatorBuilder`] builder type.
584    pub fn with_payload_validator<T>(
585        self,
586        payload_validator_builder: T,
587    ) -> RpcAddOns<Node, EthB, T, EB, EVB, RpcMiddleware> {
588        let Self {
589            hooks,
590            eth_api_builder,
591            engine_api_builder,
592            engine_validator_builder,
593            rpc_middleware,
594            tokio_runtime,
595            ..
596        } = self;
597        RpcAddOns {
598            hooks,
599            eth_api_builder,
600            payload_validator_builder,
601            engine_api_builder,
602            engine_validator_builder,
603            rpc_middleware,
604            tokio_runtime,
605        }
606    }
607
608    /// Maps the [`EngineValidatorBuilder`] builder type.
609    pub fn with_engine_validator<T>(
610        self,
611        engine_validator_builder: T,
612    ) -> RpcAddOns<Node, EthB, PVB, EB, T, RpcMiddleware> {
613        let Self {
614            hooks,
615            eth_api_builder,
616            payload_validator_builder,
617            engine_api_builder,
618            rpc_middleware,
619            tokio_runtime,
620            ..
621        } = self;
622        RpcAddOns {
623            hooks,
624            eth_api_builder,
625            payload_validator_builder,
626            engine_api_builder,
627            engine_validator_builder,
628            rpc_middleware,
629            tokio_runtime,
630        }
631    }
632
633    /// Sets the RPC middleware stack for processing RPC requests.
634    ///
635    /// This method configures a custom middleware stack that will be applied to all RPC requests
636    /// across HTTP, `WebSocket`, and IPC transports. The middleware is applied to the RPC service
637    /// layer, allowing you to intercept, modify, or enhance RPC request processing.
638    ///
639    ///
640    /// # How It Works
641    ///
642    /// The middleware uses the Tower ecosystem's `Layer` pattern. When an RPC server is started,
643    /// the configured middleware stack is applied to create a layered service that processes
644    /// requests in the order the layers were added.
645    ///
646    /// # Examples
647    ///
648    /// ```ignore
649    /// use reth_rpc_builder::{RpcServiceBuilder, RpcRequestMetrics};
650    /// use tower::Layer;
651    ///
652    /// // Simple example with metrics
653    /// let metrics_layer = RpcRequestMetrics::new(metrics_recorder);
654    /// let with_metrics = rpc_addons.with_rpc_middleware(
655    ///     RpcServiceBuilder::new().layer(metrics_layer)
656    /// );
657    ///
658    /// // Composing multiple middleware layers
659    /// let middleware_stack = RpcServiceBuilder::new()
660    ///     .layer(rate_limit_layer)
661    ///     .layer(logging_layer)
662    ///     .layer(metrics_layer);
663    /// let with_full_stack = rpc_addons.with_rpc_middleware(middleware_stack);
664    /// ```
665    ///
666    /// # Notes
667    ///
668    /// - Middleware is applied to the RPC service layer, not the HTTP transport layer
669    /// - The default middleware is `Identity` (no-op), which passes through requests unchanged
670    /// - Middleware layers are applied in the order they are added via `.layer()`
671    pub fn with_rpc_middleware<T>(
672        self,
673        rpc_middleware: T,
674    ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, T> {
675        let Self {
676            hooks,
677            eth_api_builder,
678            payload_validator_builder,
679            engine_api_builder,
680            engine_validator_builder,
681            tokio_runtime,
682            ..
683        } = self;
684        RpcAddOns {
685            hooks,
686            eth_api_builder,
687            payload_validator_builder,
688            engine_api_builder,
689            engine_validator_builder,
690            rpc_middleware,
691            tokio_runtime,
692        }
693    }
694
695    /// Sets the tokio runtime for the RPC servers.
696    ///
697    /// Caution: This runtime must not be created from within asynchronous context.
698    pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
699        let Self {
700            hooks,
701            eth_api_builder,
702            payload_validator_builder,
703            engine_validator_builder,
704            engine_api_builder,
705            rpc_middleware,
706            ..
707        } = self;
708        Self {
709            hooks,
710            eth_api_builder,
711            payload_validator_builder,
712            engine_validator_builder,
713            engine_api_builder,
714            rpc_middleware,
715            tokio_runtime,
716        }
717    }
718
719    /// Add a new layer `T` to the configured [`RpcServiceBuilder`].
720    pub fn layer_rpc_middleware<T>(
721        self,
722        layer: T,
723    ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, T>> {
724        let Self {
725            hooks,
726            eth_api_builder,
727            payload_validator_builder,
728            engine_api_builder,
729            engine_validator_builder,
730            rpc_middleware,
731            tokio_runtime,
732        } = self;
733        let rpc_middleware = Stack::new(rpc_middleware, layer);
734        RpcAddOns {
735            hooks,
736            eth_api_builder,
737            payload_validator_builder,
738            engine_api_builder,
739            engine_validator_builder,
740            rpc_middleware,
741            tokio_runtime,
742        }
743    }
744
745    /// Optionally adds a new layer `T` to the configured [`RpcServiceBuilder`].
746    #[expect(clippy::type_complexity)]
747    pub fn option_layer_rpc_middleware<T>(
748        self,
749        layer: Option<T>,
750    ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, Either<T, Identity>>> {
751        let layer = layer.map(Either::Left).unwrap_or(Either::Right(Identity::new()));
752        self.layer_rpc_middleware(layer)
753    }
754
755    /// Sets the hook that is run once the rpc server is started.
756    pub fn on_rpc_started<F>(mut self, hook: F) -> Self
757    where
758        F: FnOnce(RpcContext<'_, Node, EthB::EthApi>, RethRpcServerHandles) -> eyre::Result<()>
759            + Send
760            + 'static,
761    {
762        self.hooks.set_on_rpc_started(hook);
763        self
764    }
765
766    /// Sets the hook that is run to configure the rpc modules.
767    pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
768    where
769        F: FnOnce(RpcContext<'_, Node, EthB::EthApi>) -> eyre::Result<()> + Send + 'static,
770    {
771        self.hooks.set_extend_rpc_modules(hook);
772        self
773    }
774}
775
776impl<Node, EthB, EV, EB, Engine> Default for RpcAddOns<Node, EthB, EV, EB, Engine, Identity>
777where
778    Node: FullNodeComponents,
779    EthB: EthApiBuilder<Node>,
780    EV: Default,
781    EB: Default,
782    Engine: Default,
783{
784    fn default() -> Self {
785        Self::new(
786            EthB::default(),
787            EV::default(),
788            EB::default(),
789            Engine::default(),
790            Default::default(),
791        )
792    }
793}
794
795impl<N, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
796where
797    N: FullNodeComponents,
798    N::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
799    EthB: EthApiBuilder<N>,
800    EB: EngineApiBuilder<N>,
801    EVB: EngineValidatorBuilder<N>,
802    RpcMiddleware: RethRpcMiddleware,
803{
804    /// Launches only the regular RPC server (HTTP/WS/IPC), without the authenticated Engine API
805    /// server.
806    ///
807    /// This is useful when you only need the regular RPC functionality and want to avoid
808    /// starting the auth server.
809    pub async fn launch_rpc_server<F>(
810        self,
811        ctx: AddOnsContext<'_, N>,
812        ext: F,
813    ) -> eyre::Result<RpcServerOnlyHandle<N, EthB::EthApi>>
814    where
815        F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
816    {
817        let rpc_middleware = self.rpc_middleware.clone();
818        let tokio_runtime = self.tokio_runtime.clone();
819        let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
820        let RpcSetupContext {
821            node,
822            config,
823            mut modules,
824            mut auth_module,
825            auth_config: _,
826            mut registry,
827            on_rpc_started,
828            engine_events,
829            engine_handle,
830        } = setup_ctx;
831
832        let server_config = config
833            .rpc
834            .rpc_server_config()
835            .set_rpc_middleware(rpc_middleware)
836            .with_tokio_runtime(tokio_runtime);
837        let rpc_server_handle = Self::launch_rpc_server_internal(server_config, &modules).await?;
838
839        let handles =
840            RethRpcServerHandles { rpc: rpc_server_handle.clone(), auth: AuthServerHandle::noop() };
841        Self::finalize_rpc_setup(
842            &mut registry,
843            &mut modules,
844            &mut auth_module,
845            &node,
846            config,
847            on_rpc_started,
848            handles,
849        )?;
850
851        Ok(RpcServerOnlyHandle {
852            rpc_server_handle,
853            rpc_registry: registry,
854            engine_events,
855            engine_handle,
856        })
857    }
858
859    /// Launches the RPC servers with the given context and an additional hook for extending
860    /// modules. Whether the auth server is launched depends on the CLI configuration.
861    pub async fn launch_add_ons_with<F>(
862        self,
863        ctx: AddOnsContext<'_, N>,
864        ext: F,
865    ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
866    where
867        F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
868    {
869        // Check CLI config to determine if auth server should be disabled
870        let disable_auth = ctx.config.rpc.disable_auth_server;
871        self.launch_add_ons_with_opt_engine(ctx, ext, disable_auth).await
872    }
873
874    /// Launches the RPC servers with the given context and an additional hook for extending
875    /// modules. Optionally disables the auth server based on the `disable_auth` parameter.
876    ///
877    /// When `disable_auth` is true, the auth server will not be started and a noop handle
878    /// will be used instead.
879    pub async fn launch_add_ons_with_opt_engine<F>(
880        self,
881        ctx: AddOnsContext<'_, N>,
882        ext: F,
883        disable_auth: bool,
884    ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
885    where
886        F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
887    {
888        let rpc_middleware = self.rpc_middleware.clone();
889        let tokio_runtime = self.tokio_runtime.clone();
890        let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
891        let RpcSetupContext {
892            node,
893            config,
894            mut modules,
895            mut auth_module,
896            auth_config,
897            mut registry,
898            on_rpc_started,
899            engine_events,
900            engine_handle,
901        } = setup_ctx;
902
903        let server_config = config
904            .rpc
905            .rpc_server_config()
906            .set_rpc_middleware(rpc_middleware)
907            .with_tokio_runtime(tokio_runtime);
908
909        let (rpc, auth) = if disable_auth {
910            // Only launch the RPC server, use a noop auth handle
911            let rpc = Self::launch_rpc_server_internal(server_config, &modules).await?;
912            (rpc, AuthServerHandle::noop())
913        } else {
914            let auth_module_clone = auth_module.clone();
915            // launch servers concurrently
916            let (rpc, auth) = futures::future::try_join(
917                Self::launch_rpc_server_internal(server_config, &modules),
918                Self::launch_auth_server_internal(auth_module_clone, auth_config),
919            )
920            .await?;
921            (rpc, auth)
922        };
923
924        let handles = RethRpcServerHandles { rpc, auth };
925
926        Self::finalize_rpc_setup(
927            &mut registry,
928            &mut modules,
929            &mut auth_module,
930            &node,
931            config,
932            on_rpc_started,
933            handles.clone(),
934        )?;
935
936        Ok(RpcHandle {
937            rpc_server_handles: handles,
938            rpc_registry: registry,
939            engine_events,
940            beacon_engine_handle: engine_handle,
941        })
942    }
943
944    /// Common setup for RPC server initialization
945    async fn setup_rpc_components<'a, F>(
946        self,
947        ctx: AddOnsContext<'a, N>,
948        ext: F,
949    ) -> eyre::Result<RpcSetupContext<'a, N, EthB::EthApi>>
950    where
951        F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
952    {
953        let Self { eth_api_builder, engine_api_builder, hooks, .. } = self;
954
955        let engine_api = engine_api_builder.build_engine_api(&ctx).await?;
956        let AddOnsContext { node, config, beacon_engine_handle, jwt_secret, engine_events } = ctx;
957
958        info!(target: "reth::cli", "Engine API handler initialized");
959
960        let cache = EthStateCache::spawn_with(
961            node.provider().clone(),
962            config.rpc.eth_config().cache,
963            node.task_executor().clone(),
964        );
965
966        let new_canonical_blocks = node.provider().canonical_state_stream();
967        let c = cache.clone();
968        node.task_executor().spawn_critical(
969            "cache canonical blocks task",
970            Box::pin(async move {
971                cache_new_blocks_task(c, new_canonical_blocks).await;
972            }),
973        );
974
975        let eth_config = config.rpc.eth_config().max_batch_size(config.txpool.max_batch_size());
976        let ctx = EthApiCtx { components: &node, config: eth_config, cache };
977        let eth_api = eth_api_builder.build_eth_api(ctx).await?;
978
979        let auth_config = config.rpc.auth_server_config(jwt_secret)?;
980        let module_config = config.rpc.transport_rpc_module_config();
981        debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config");
982
983        let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
984            .with_provider(node.provider().clone())
985            .with_pool(node.pool().clone())
986            .with_network(node.network().clone())
987            .with_executor(Box::new(node.task_executor().clone()))
988            .with_evm_config(node.evm_config().clone())
989            .with_consensus(node.consensus().clone())
990            .build_with_auth_server(module_config, engine_api, eth_api);
991
992        // in dev mode we generate 20 random dev-signer accounts
993        if config.dev.dev {
994            registry.eth_api().with_dev_accounts();
995        }
996
997        let mut registry = RpcRegistry { registry };
998        let ctx = RpcContext {
999            node: node.clone(),
1000            config,
1001            registry: &mut registry,
1002            modules: &mut modules,
1003            auth_module: &mut auth_module,
1004        };
1005
1006        let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
1007
1008        ext(RpcModuleContainer {
1009            modules: ctx.modules,
1010            auth_module: ctx.auth_module,
1011            registry: ctx.registry,
1012        })?;
1013        extend_rpc_modules.extend_rpc_modules(ctx)?;
1014
1015        Ok(RpcSetupContext {
1016            node,
1017            config,
1018            modules,
1019            auth_module,
1020            auth_config,
1021            registry,
1022            on_rpc_started,
1023            engine_events,
1024            engine_handle: beacon_engine_handle,
1025        })
1026    }
1027
1028    /// Helper to launch the RPC server
1029    async fn launch_rpc_server_internal<M>(
1030        server_config: RpcServerConfig<M>,
1031        modules: &TransportRpcModules,
1032    ) -> eyre::Result<RpcServerHandle>
1033    where
1034        M: RethRpcMiddleware,
1035    {
1036        let handle = server_config.start(modules).await?;
1037
1038        if let Some(path) = handle.ipc_endpoint() {
1039            info!(target: "reth::cli", %path, "RPC IPC server started");
1040        }
1041        if let Some(addr) = handle.http_local_addr() {
1042            info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
1043        }
1044        if let Some(addr) = handle.ws_local_addr() {
1045            info!(target: "reth::cli", url=%addr, "RPC WS server started");
1046        }
1047
1048        Ok(handle)
1049    }
1050
1051    /// Helper to launch the auth server
1052    async fn launch_auth_server_internal(
1053        auth_module: AuthRpcModule,
1054        auth_config: reth_rpc_builder::auth::AuthServerConfig,
1055    ) -> eyre::Result<AuthServerHandle> {
1056        auth_module.start_server(auth_config)
1057            .await
1058            .map_err(Into::into)
1059            .inspect(|handle| {
1060                let addr = handle.local_addr();
1061                if let Some(ipc_endpoint) = handle.ipc_endpoint() {
1062                    info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
1063                } else {
1064                    info!(target: "reth::cli", url=%addr, "RPC auth server started");
1065                }
1066            })
1067    }
1068
1069    /// Helper to finalize RPC setup by creating context and calling hooks
1070    fn finalize_rpc_setup(
1071        registry: &mut RpcRegistry<N, EthB::EthApi>,
1072        modules: &mut TransportRpcModules,
1073        auth_module: &mut AuthRpcModule,
1074        node: &N,
1075        config: &NodeConfig<<N::Types as NodeTypes>::ChainSpec>,
1076        on_rpc_started: Box<dyn OnRpcStarted<N, EthB::EthApi>>,
1077        handles: RethRpcServerHandles,
1078    ) -> eyre::Result<()> {
1079        let ctx = RpcContext { node: node.clone(), config, registry, modules, auth_module };
1080
1081        on_rpc_started.on_rpc_started(ctx, handles)?;
1082        Ok(())
1083    }
1084}
1085
1086impl<N, EthB, PVB, EB, EVB, RpcMiddleware> NodeAddOns<N>
1087    for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1088where
1089    N: FullNodeComponents,
1090    <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
1091    EthB: EthApiBuilder<N>,
1092    PVB: PayloadValidatorBuilder<N>,
1093    EB: EngineApiBuilder<N>,
1094    EVB: EngineValidatorBuilder<N>,
1095    RpcMiddleware: RethRpcMiddleware,
1096{
1097    type Handle = RpcHandle<N, EthB::EthApi>;
1098
1099    async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
1100        self.launch_add_ons_with(ctx, |_| Ok(())).await
1101    }
1102}
1103
1104/// Helper trait implemented for add-ons producing [`RpcHandle`]. Used by common node launcher
1105/// implementations.
1106pub trait RethRpcAddOns<N: FullNodeComponents>:
1107    NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
1108{
1109    /// eth API implementation.
1110    type EthApi: EthApiTypes;
1111
1112    /// Returns a mutable reference to RPC hooks.
1113    fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
1114}
1115
1116impl<N: FullNodeComponents, EthB, EV, EB, Engine, RpcMiddleware> RethRpcAddOns<N>
1117    for RpcAddOns<N, EthB, EV, EB, Engine, RpcMiddleware>
1118where
1119    Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
1120    EthB: EthApiBuilder<N>,
1121{
1122    type EthApi = EthB::EthApi;
1123
1124    fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
1125        &mut self.hooks
1126    }
1127}
1128
1129/// `EthApiCtx` struct
1130/// This struct is used to pass the necessary context to the `EthApiBuilder` to build the `EthApi`.
1131#[derive(Debug)]
1132pub struct EthApiCtx<'a, N: FullNodeTypes> {
1133    /// Reference to the node components
1134    pub components: &'a N,
1135    /// Eth API configuration
1136    pub config: EthConfig,
1137    /// Cache for eth state
1138    pub cache: EthStateCache<PrimitivesTy<N::Types>>,
1139}
1140
1141impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>>>
1142    EthApiCtx<'a, N>
1143{
1144    /// Provides a [`EthApiBuilder`] with preconfigured config and components.
1145    pub fn eth_api_builder(self) -> reth_rpc::EthApiBuilder<N, EthRpcConverterFor<N>> {
1146        reth_rpc::EthApiBuilder::new_with_components(self.components.clone())
1147            .eth_cache(self.cache)
1148            .task_spawner(self.components.task_executor().clone())
1149            .gas_cap(self.config.rpc_gas_cap.into())
1150            .max_simulate_blocks(self.config.rpc_max_simulate_blocks)
1151            .eth_proof_window(self.config.eth_proof_window)
1152            .fee_history_cache_config(self.config.fee_history_cache)
1153            .proof_permits(self.config.proof_permits)
1154            .gas_oracle_config(self.config.gas_oracle)
1155            .max_batch_size(self.config.max_batch_size)
1156            .pending_block_kind(self.config.pending_block_kind)
1157            .raw_tx_forwarder(self.config.raw_tx_forwarder)
1158    }
1159}
1160
1161/// A `EthApi` that knows how to build `eth` namespace API from [`FullNodeComponents`].
1162pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
1163    /// The Ethapi implementation this builder will build.
1164    type EthApi: EthApiTypes
1165        + FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
1166        + AddDevSigners
1167        + Unpin
1168        + 'static;
1169
1170    /// Builds the [`EthApiServer`](reth_rpc_api::eth::EthApiServer) from the given context.
1171    fn build_eth_api(
1172        self,
1173        ctx: EthApiCtx<'_, N>,
1174    ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
1175}
1176
1177/// Helper trait that provides the validator builder for the engine API
1178pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
1179    /// The validator builder type to use.
1180    type ValidatorBuilder: EngineValidatorBuilder<Node>;
1181
1182    /// Returns the validator builder.
1183    fn engine_validator_builder(&self) -> Self::ValidatorBuilder;
1184}
1185
1186impl<N, EthB, PVB, EB, EVB, RpcMiddleware> EngineValidatorAddOn<N>
1187    for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1188where
1189    N: FullNodeComponents,
1190    EthB: EthApiBuilder<N>,
1191    PVB: Send,
1192    EB: EngineApiBuilder<N>,
1193    EVB: EngineValidatorBuilder<N>,
1194    RpcMiddleware: Send,
1195{
1196    type ValidatorBuilder = EVB;
1197
1198    fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
1199        self.engine_validator_builder.clone()
1200    }
1201}
1202
1203/// Builder for engine API RPC module.
1204///
1205/// This builder type is responsible for providing an instance of [`IntoEngineApiRpcModule`], which
1206/// is effectively a helper trait that provides the type erased [`jsonrpsee::RpcModule`] instance
1207/// that contains the method handlers for the engine API. See [`EngineApi`] for an implementation of
1208/// [`IntoEngineApiRpcModule`].
1209pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
1210    /// The engine API RPC module. Only required to be convertible to an [`jsonrpsee::RpcModule`].
1211    type EngineApi: IntoEngineApiRpcModule + Send + Sync;
1212
1213    /// Builds the engine API instance given the provided [`AddOnsContext`].
1214    ///
1215    /// [`Self::EngineApi`] will be converted into the method handlers of the authenticated RPC
1216    /// server (engine API).
1217    fn build_engine_api(
1218        self,
1219        ctx: &AddOnsContext<'_, Node>,
1220    ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
1221}
1222
1223/// Builder trait for creating payload validators specifically for the Engine API.
1224///
1225/// This trait is responsible for building validators that the Engine API will use
1226/// to validate payloads.
1227pub trait PayloadValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1228    /// The validator type that will be used by the Engine API.
1229    type Validator: PayloadValidator<<Node::Types as NodeTypes>::Payload>;
1230
1231    /// Builds the engine API validator.
1232    ///
1233    /// Returns a validator that validates engine API version-specific fields and payload
1234    /// attributes.
1235    fn build(
1236        self,
1237        ctx: &AddOnsContext<'_, Node>,
1238    ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
1239}
1240
1241/// Builder trait for creating engine validators for the consensus engine.
1242///
1243/// This trait is responsible for building validators that the consensus engine will use
1244/// for block execution, state validation, and fork handling.
1245pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1246    /// The tree validator type that will be used by the consensus engine.
1247    type EngineValidator: EngineValidator<
1248        <Node::Types as NodeTypes>::Payload,
1249        <Node::Types as NodeTypes>::Primitives,
1250    >;
1251
1252    /// Builds the tree validator for the consensus engine.
1253    ///
1254    /// Returns a validator that handles block execution, state validation, and fork handling.
1255    fn build_tree_validator(
1256        self,
1257        ctx: &AddOnsContext<'_, Node>,
1258        tree_config: TreeConfig,
1259    ) -> impl Future<Output = eyre::Result<Self::EngineValidator>> + Send;
1260}
1261
1262/// Basic implementation of [`EngineValidatorBuilder`].
1263///
1264/// This builder creates a [`BasicEngineValidator`] using the provided payload validator builder.
1265#[derive(Debug, Clone)]
1266pub struct BasicEngineValidatorBuilder<EV> {
1267    /// The payload validator builder used to create the engine validator.
1268    payload_validator_builder: EV,
1269}
1270
1271impl<EV> BasicEngineValidatorBuilder<EV> {
1272    /// Creates a new instance with the given payload validator builder.
1273    pub const fn new(payload_validator_builder: EV) -> Self {
1274        Self { payload_validator_builder }
1275    }
1276}
1277
1278impl<EV> Default for BasicEngineValidatorBuilder<EV>
1279where
1280    EV: Default,
1281{
1282    fn default() -> Self {
1283        Self::new(EV::default())
1284    }
1285}
1286
1287impl<Node, EV> EngineValidatorBuilder<Node> for BasicEngineValidatorBuilder<EV>
1288where
1289    Node: FullNodeComponents<
1290        Evm: ConfigureEngineEvm<
1291            <<Node::Types as NodeTypes>::Payload as PayloadTypes>::ExecutionData,
1292        >,
1293    >,
1294    EV: PayloadValidatorBuilder<Node>,
1295    EV::Validator: reth_engine_primitives::PayloadValidator<
1296        <Node::Types as NodeTypes>::Payload,
1297        Block = BlockTy<Node::Types>,
1298    >,
1299{
1300    type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
1301
1302    async fn build_tree_validator(
1303        self,
1304        ctx: &AddOnsContext<'_, Node>,
1305        tree_config: TreeConfig,
1306    ) -> eyre::Result<Self::EngineValidator> {
1307        let validator = self.payload_validator_builder.build(ctx).await?;
1308        let data_dir = ctx.config.datadir.clone().resolve_datadir(ctx.config.chain.chain());
1309        let invalid_block_hook = ctx.create_invalid_block_hook(&data_dir).await?;
1310        Ok(BasicEngineValidator::new(
1311            ctx.node.provider().clone(),
1312            std::sync::Arc::new(ctx.node.consensus().clone()),
1313            ctx.node.evm_config().clone(),
1314            validator,
1315            tree_config,
1316            invalid_block_hook,
1317        ))
1318    }
1319}
1320
1321/// Builder for basic [`EngineApi`] implementation.
1322///
1323/// This provides a basic default implementation for opstack and ethereum engine API via
1324/// [`EngineTypes`] and uses the general purpose [`EngineApi`] implementation as the builder's
1325/// output.
1326#[derive(Debug, Default)]
1327pub struct BasicEngineApiBuilder<PVB> {
1328    payload_validator_builder: PVB,
1329}
1330
1331impl<N, PVB> EngineApiBuilder<N> for BasicEngineApiBuilder<PVB>
1332where
1333    N: FullNodeComponents<
1334        Types: NodeTypes<
1335            ChainSpec: EthereumHardforks,
1336            Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
1337        >,
1338    >,
1339    PVB: PayloadValidatorBuilder<N>,
1340    PVB::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
1341{
1342    type EngineApi = EngineApi<
1343        N::Provider,
1344        <N::Types as NodeTypes>::Payload,
1345        N::Pool,
1346        PVB::Validator,
1347        <N::Types as NodeTypes>::ChainSpec,
1348    >;
1349
1350    async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1351        let Self { payload_validator_builder } = self;
1352
1353        let engine_validator = payload_validator_builder.build(ctx).await?;
1354        let client = ClientVersionV1 {
1355            code: CLIENT_CODE,
1356            name: version_metadata().name_client.to_string(),
1357            version: version_metadata().cargo_pkg_version.to_string(),
1358            commit: version_metadata().vergen_git_sha.to_string(),
1359        };
1360        Ok(EngineApi::new(
1361            ctx.node.provider().clone(),
1362            ctx.config.chain.clone(),
1363            ctx.beacon_engine_handle.clone(),
1364            PayloadStore::new(ctx.node.payload_builder_handle().clone()),
1365            ctx.node.pool().clone(),
1366            Box::new(ctx.node.task_executor().clone()),
1367            client,
1368            EngineCapabilities::default(),
1369            engine_validator,
1370            ctx.config.engine.accept_execution_requests_hash,
1371        ))
1372    }
1373}
1374
1375/// A noop Builder that satisfies the [`EngineApiBuilder`] trait without actually configuring an
1376/// engine API module
1377///
1378/// This is intended to be used as a workaround for reusing all the existing ethereum node launch
1379/// utilities which require an engine API.
1380#[derive(Debug, Clone, Default)]
1381#[non_exhaustive]
1382pub struct NoopEngineApiBuilder;
1383
1384impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
1385    type EngineApi = NoopEngineApi;
1386
1387    async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1388        Ok(NoopEngineApi::default())
1389    }
1390}
1391
1392/// Represents an empty Engine API [`RpcModule`].
1393///
1394/// This is only intended to be used in combination with the [`NoopEngineApiBuilder`] in order to
1395/// satisfy trait bounds in the regular ethereum launch routine that mandate an engine API instance.
1396#[derive(Debug, Clone, Default)]
1397#[non_exhaustive]
1398pub struct NoopEngineApi;
1399
1400impl IntoEngineApiRpcModule for NoopEngineApi {
1401    fn into_rpc_module(self) -> RpcModule<()> {
1402        RpcModule::new(())
1403    }
1404}