Skip to main content

reth_node_builder/
rpc.rs

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