Skip to main content

reth_node_builder/
rpc.rs

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