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