reth_node_builder/
rpc.rs

1//! Builder support for rpc components.
2
3use crate::{BeaconConsensusEngineEvent, BeaconConsensusEngineHandle};
4use alloy_rpc_types::engine::ClientVersionV1;
5use alloy_rpc_types_engine::ExecutionData;
6use futures::TryFutureExt;
7use jsonrpsee::RpcModule;
8use reth_chain_state::CanonStateSubscriptions;
9use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
10use reth_node_api::{
11    AddOnsContext, BlockTy, EngineTypes, EngineValidator, FullNodeComponents, FullNodeTypes,
12    NodeAddOns, NodeTypes, PayloadTypes, ReceiptTy,
13};
14use reth_node_core::{
15    node_config::NodeConfig,
16    version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA},
17};
18use reth_payload_builder::{PayloadBuilderHandle, PayloadStore};
19use reth_rpc::eth::{EthApiTypes, FullEthApiServer};
20use reth_rpc_api::{eth::helpers::AddDevSigners, IntoEngineApiRpcModule};
21use reth_rpc_builder::{
22    auth::{AuthRpcModule, AuthServerHandle},
23    config::RethRpcServerConfig,
24    RpcModuleBuilder, RpcRegistryInner, RpcServerHandle, TransportRpcModules,
25};
26use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
27use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
28use reth_tokio_util::EventSender;
29use reth_tracing::tracing::{debug, info};
30use std::{
31    fmt::{self, Debug},
32    future::Future,
33    ops::{Deref, DerefMut},
34};
35
36/// Contains the handles to the spawned RPC servers.
37///
38/// This can be used to access the endpoints of the servers.
39#[derive(Debug, Clone)]
40pub struct RethRpcServerHandles {
41    /// The regular RPC server handle to all configured transports.
42    pub rpc: RpcServerHandle,
43    /// The handle to the auth server (engine API)
44    pub auth: AuthServerHandle,
45}
46
47/// Contains hooks that are called during the rpc setup.
48pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
49    /// Hooks to run once RPC server is running.
50    pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
51    /// Hooks to run to configure RPC server API.
52    pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
53}
54
55impl<Node, EthApi> Default for RpcHooks<Node, EthApi>
56where
57    Node: FullNodeComponents,
58    EthApi: EthApiTypes,
59{
60    fn default() -> Self {
61        Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
62    }
63}
64
65impl<Node, EthApi> RpcHooks<Node, EthApi>
66where
67    Node: FullNodeComponents,
68    EthApi: EthApiTypes,
69{
70    /// Sets the hook that is run once the rpc server is started.
71    pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
72    where
73        F: OnRpcStarted<Node, EthApi> + 'static,
74    {
75        self.on_rpc_started = Box::new(hook);
76        self
77    }
78
79    /// Sets the hook that is run once the rpc server is started.
80    #[expect(unused)]
81    pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
82    where
83        F: OnRpcStarted<Node, EthApi> + 'static,
84    {
85        self.set_on_rpc_started(hook);
86        self
87    }
88
89    /// Sets the hook that is run to configure the rpc modules.
90    pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
91    where
92        F: ExtendRpcModules<Node, EthApi> + 'static,
93    {
94        self.extend_rpc_modules = Box::new(hook);
95        self
96    }
97
98    /// Sets the hook that is run to configure the rpc modules.
99    #[expect(unused)]
100    pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
101    where
102        F: ExtendRpcModules<Node, EthApi> + 'static,
103    {
104        self.set_extend_rpc_modules(hook);
105        self
106    }
107}
108
109impl<Node, EthApi> fmt::Debug for RpcHooks<Node, EthApi>
110where
111    Node: FullNodeComponents,
112    EthApi: EthApiTypes,
113{
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.debug_struct("RpcHooks")
116            .field("on_rpc_started", &"...")
117            .field("extend_rpc_modules", &"...")
118            .finish()
119    }
120}
121
122/// Event hook that is called once the rpc server is started.
123pub trait OnRpcStarted<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
124    /// The hook that is called once the rpc server is started.
125    fn on_rpc_started(
126        self: Box<Self>,
127        ctx: RpcContext<'_, Node, EthApi>,
128        handles: RethRpcServerHandles,
129    ) -> eyre::Result<()>;
130}
131
132impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
133where
134    F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
135    Node: FullNodeComponents,
136    EthApi: EthApiTypes,
137{
138    fn on_rpc_started(
139        self: Box<Self>,
140        ctx: RpcContext<'_, Node, EthApi>,
141        handles: RethRpcServerHandles,
142    ) -> eyre::Result<()> {
143        (*self)(ctx, handles)
144    }
145}
146
147impl<Node, EthApi> OnRpcStarted<Node, EthApi> for ()
148where
149    Node: FullNodeComponents,
150    EthApi: EthApiTypes,
151{
152    fn on_rpc_started(
153        self: Box<Self>,
154        _: RpcContext<'_, Node, EthApi>,
155        _: RethRpcServerHandles,
156    ) -> eyre::Result<()> {
157        Ok(())
158    }
159}
160
161/// Event hook that is called when the rpc server is started.
162pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
163    /// The hook that is called once the rpc server is started.
164    fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
165}
166
167impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
168where
169    F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
170    Node: FullNodeComponents,
171    EthApi: EthApiTypes,
172{
173    fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
174        (*self)(ctx)
175    }
176}
177
178impl<Node, EthApi> ExtendRpcModules<Node, EthApi> for ()
179where
180    Node: FullNodeComponents,
181    EthApi: EthApiTypes,
182{
183    fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
184        Ok(())
185    }
186}
187
188/// Helper wrapper type to encapsulate the [`RpcRegistryInner`] over components trait.
189#[derive(Debug, Clone)]
190#[expect(clippy::type_complexity)]
191pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
192    pub(crate) registry: RpcRegistryInner<
193        Node::Provider,
194        Node::Pool,
195        Node::Network,
196        EthApi,
197        Node::Evm,
198        Node::Consensus,
199    >,
200}
201
202impl<Node, EthApi> Deref for RpcRegistry<Node, EthApi>
203where
204    Node: FullNodeComponents,
205    EthApi: EthApiTypes,
206{
207    type Target = RpcRegistryInner<
208        Node::Provider,
209        Node::Pool,
210        Node::Network,
211        EthApi,
212        Node::Evm,
213        Node::Consensus,
214    >;
215
216    fn deref(&self) -> &Self::Target {
217        &self.registry
218    }
219}
220
221impl<Node, EthApi> DerefMut for RpcRegistry<Node, EthApi>
222where
223    Node: FullNodeComponents,
224    EthApi: EthApiTypes,
225{
226    fn deref_mut(&mut self) -> &mut Self::Target {
227        &mut self.registry
228    }
229}
230
231/// Helper container to encapsulate [`RpcRegistryInner`], [`TransportRpcModules`] and
232/// [`AuthRpcModule`].
233///
234/// This can be used to access installed modules, or create commonly used handlers like
235/// [`reth_rpc::eth::EthApi`], and ultimately merge additional rpc handler into the configured
236/// transport modules [`TransportRpcModules`] as well as configured authenticated methods
237/// [`AuthRpcModule`].
238#[expect(missing_debug_implementations)]
239pub struct RpcContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
240    /// The node components.
241    pub(crate) node: Node,
242
243    /// Gives access to the node configuration.
244    pub(crate) config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
245
246    /// A Helper type the holds instances of the configured modules.
247    ///
248    /// This provides easy access to rpc handlers, such as [`RpcRegistryInner::eth_api`].
249    pub registry: &'a mut RpcRegistry<Node, EthApi>,
250    /// Holds installed modules per transport type.
251    ///
252    /// This can be used to merge additional modules into the configured transports (http, ipc,
253    /// ws). See [`TransportRpcModules::merge_configured`]
254    pub modules: &'a mut TransportRpcModules,
255    /// Holds jwt authenticated rpc module.
256    ///
257    /// This can be used to merge additional modules into the configured authenticated methods
258    pub auth_module: &'a mut AuthRpcModule,
259}
260
261impl<Node, EthApi> RpcContext<'_, Node, EthApi>
262where
263    Node: FullNodeComponents,
264    EthApi: EthApiTypes,
265{
266    /// Returns the config of the node.
267    pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
268        self.config
269    }
270
271    /// Returns a reference to the configured node.
272    pub const fn node(&self) -> &Node {
273        &self.node
274    }
275
276    /// Returns the transaction pool instance.
277    pub fn pool(&self) -> &Node::Pool {
278        self.node.pool()
279    }
280
281    /// Returns provider to interact with the node.
282    pub fn provider(&self) -> &Node::Provider {
283        self.node.provider()
284    }
285
286    /// Returns the handle to the network
287    pub fn network(&self) -> &Node::Network {
288        self.node.network()
289    }
290
291    /// Returns the handle to the payload builder service
292    pub fn payload_builder_handle(
293        &self,
294    ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
295        self.node.payload_builder_handle()
296    }
297}
298
299/// Handle to the launched RPC servers.
300pub struct RpcHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
301    /// Handles to launched servers.
302    pub rpc_server_handles: RethRpcServerHandles,
303    /// Configured RPC modules.
304    pub rpc_registry: RpcRegistry<Node, EthApi>,
305    /// Notification channel for engine API events
306    ///
307    /// Caution: This is a multi-producer, multi-consumer broadcast and allows grants access to
308    /// dispatch events
309    pub engine_events:
310        EventSender<BeaconConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
311    /// Handle to the beacon consensus engine.
312    pub beacon_engine_handle: BeaconConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
313}
314
315impl<Node: FullNodeComponents, EthApi: EthApiTypes> Clone for RpcHandle<Node, EthApi> {
316    fn clone(&self) -> Self {
317        Self {
318            rpc_server_handles: self.rpc_server_handles.clone(),
319            rpc_registry: self.rpc_registry.clone(),
320            engine_events: self.engine_events.clone(),
321            beacon_engine_handle: self.beacon_engine_handle.clone(),
322        }
323    }
324}
325
326impl<Node: FullNodeComponents, EthApi: EthApiTypes> Deref for RpcHandle<Node, EthApi> {
327    type Target = RpcRegistry<Node, EthApi>;
328
329    fn deref(&self) -> &Self::Target {
330        &self.rpc_registry
331    }
332}
333
334impl<Node: FullNodeComponents, EthApi: EthApiTypes> Debug for RpcHandle<Node, EthApi>
335where
336    RpcRegistry<Node, EthApi>: Debug,
337{
338    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
339        f.debug_struct("RpcHandle")
340            .field("rpc_server_handles", &self.rpc_server_handles)
341            .field("rpc_registry", &self.rpc_registry)
342            .finish()
343    }
344}
345
346/// Node add-ons containing RPC server configuration, with customizable eth API handler.
347///
348/// This struct can be used to provide the RPC server functionality. It is responsible for launching
349/// the regular RPC and the authenticated RPC server (engine API). It is intended to be used and
350/// modified as part of the [`NodeAddOns`] see for example `OpRpcAddons`, `EthereumAddOns`.
351///
352/// It can be modified to register RPC API handlers, see [`RpcAddOns::launch_add_ons_with`] which
353/// takes a closure that provides access to all the configured modules (namespaces), and is invoked
354/// just before the servers are launched. This can be used to extend the node with custom RPC
355/// methods or even replace existing method handlers, see also [`TransportRpcModules`].
356pub struct RpcAddOns<
357    Node: FullNodeComponents,
358    EthB: EthApiBuilder<Node>,
359    EV,
360    EB = BasicEngineApiBuilder<EV>,
361> {
362    /// Additional RPC add-ons.
363    pub hooks: RpcHooks<Node, EthB::EthApi>,
364    /// Builder for `EthApi`
365    eth_api_builder: EthB,
366    /// Engine validator
367    engine_validator_builder: EV,
368    /// Builder for `EngineApi`
369    engine_api_builder: EB,
370}
371
372impl<Node, EthB, EV, EB> Debug for RpcAddOns<Node, EthB, EV, EB>
373where
374    Node: FullNodeComponents,
375    EthB: EthApiBuilder<Node>,
376    EV: Debug,
377    EB: Debug,
378{
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        f.debug_struct("RpcAddOns")
381            .field("hooks", &self.hooks)
382            .field("eth_api_builder", &"...")
383            .field("engine_validator_builder", &self.engine_validator_builder)
384            .field("engine_api_builder", &self.engine_api_builder)
385            .finish()
386    }
387}
388
389impl<Node, EthB, EV, EB> RpcAddOns<Node, EthB, EV, EB>
390where
391    Node: FullNodeComponents,
392    EthB: EthApiBuilder<Node>,
393{
394    /// Creates a new instance of the RPC add-ons.
395    pub fn new(
396        eth_api_builder: EthB,
397        engine_validator_builder: EV,
398        engine_api_builder: EB,
399    ) -> Self {
400        Self {
401            hooks: RpcHooks::default(),
402            eth_api_builder,
403            engine_validator_builder,
404            engine_api_builder,
405        }
406    }
407
408    /// Maps the [`EngineApiBuilder`] builder type.
409    pub fn with_engine_api<T>(self, engine_api_builder: T) -> RpcAddOns<Node, EthB, EV, T> {
410        let Self { hooks, eth_api_builder, engine_validator_builder, .. } = self;
411        RpcAddOns { hooks, eth_api_builder, engine_validator_builder, engine_api_builder }
412    }
413
414    /// Maps the [`EngineValidatorBuilder`] builder type.
415    pub fn with_engine_validator<T>(
416        self,
417        engine_validator_builder: T,
418    ) -> RpcAddOns<Node, EthB, T, EB> {
419        let Self { hooks, eth_api_builder, engine_api_builder, .. } = self;
420        RpcAddOns { hooks, eth_api_builder, engine_validator_builder, engine_api_builder }
421    }
422
423    /// Sets the hook that is run once the rpc server is started.
424    pub fn on_rpc_started<F>(mut self, hook: F) -> Self
425    where
426        F: FnOnce(RpcContext<'_, Node, EthB::EthApi>, RethRpcServerHandles) -> eyre::Result<()>
427            + Send
428            + 'static,
429    {
430        self.hooks.set_on_rpc_started(hook);
431        self
432    }
433
434    /// Sets the hook that is run to configure the rpc modules.
435    pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
436    where
437        F: FnOnce(RpcContext<'_, Node, EthB::EthApi>) -> eyre::Result<()> + Send + 'static,
438    {
439        self.hooks.set_extend_rpc_modules(hook);
440        self
441    }
442}
443
444impl<Node, EthB, EV, EB> Default for RpcAddOns<Node, EthB, EV, EB>
445where
446    Node: FullNodeComponents,
447    EthB: EthApiBuilder<Node>,
448    EV: Default,
449    EB: Default,
450{
451    fn default() -> Self {
452        Self::new(EthB::default(), EV::default(), EB::default())
453    }
454}
455
456impl<N, EthB, EV, EB> RpcAddOns<N, EthB, EV, EB>
457where
458    N: FullNodeComponents,
459    N::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
460    EthB: EthApiBuilder<N>,
461    EV: EngineValidatorBuilder<N>,
462    EB: EngineApiBuilder<N>,
463{
464    /// Launches the RPC servers with the given context and an additional hook for extending
465    /// modules.
466    pub async fn launch_add_ons_with<F>(
467        self,
468        ctx: AddOnsContext<'_, N>,
469        ext: F,
470    ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
471    where
472        F: FnOnce(
473            &mut TransportRpcModules,
474            &mut AuthRpcModule,
475            &mut RpcRegistry<N, EthB::EthApi>,
476        ) -> eyre::Result<()>,
477    {
478        let Self { eth_api_builder, engine_api_builder, hooks, .. } = self;
479
480        let engine_api = engine_api_builder.build_engine_api(&ctx).await?;
481        let AddOnsContext { node, config, beacon_engine_handle, jwt_secret, engine_events } = ctx;
482
483        info!(target: "reth::cli", "Engine API handler initialized");
484
485        let cache = EthStateCache::spawn_with(
486            node.provider().clone(),
487            config.rpc.eth_config().cache,
488            node.task_executor().clone(),
489        );
490
491        let new_canonical_blocks = node.provider().canonical_state_stream();
492        let c = cache.clone();
493        node.task_executor().spawn_critical(
494            "cache canonical blocks task",
495            Box::pin(async move {
496                cache_new_blocks_task(c, new_canonical_blocks).await;
497            }),
498        );
499
500        let ctx = EthApiCtx { components: &node, config: config.rpc.eth_config(), cache };
501        let eth_api = eth_api_builder.build_eth_api(ctx).await?;
502
503        let auth_config = config.rpc.auth_server_config(jwt_secret)?;
504        let module_config = config.rpc.transport_rpc_module_config();
505        debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config");
506
507        let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
508            .with_provider(node.provider().clone())
509            .with_pool(node.pool().clone())
510            .with_network(node.network().clone())
511            .with_executor(Box::new(node.task_executor().clone()))
512            .with_evm_config(node.evm_config().clone())
513            .with_consensus(node.consensus().clone())
514            .build_with_auth_server(module_config, engine_api, eth_api);
515
516        // in dev mode we generate 20 random dev-signer accounts
517        if config.dev.dev {
518            registry.eth_api().with_dev_accounts();
519        }
520
521        let mut registry = RpcRegistry { registry };
522        let ctx = RpcContext {
523            node: node.clone(),
524            config,
525            registry: &mut registry,
526            modules: &mut modules,
527            auth_module: &mut auth_module,
528        };
529
530        let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
531
532        ext(ctx.modules, ctx.auth_module, ctx.registry)?;
533        extend_rpc_modules.extend_rpc_modules(ctx)?;
534
535        let server_config = config.rpc.rpc_server_config();
536        let cloned_modules = modules.clone();
537        let launch_rpc = server_config.start(&cloned_modules).map_ok(|handle| {
538            if let Some(path) = handle.ipc_endpoint() {
539                info!(target: "reth::cli", %path, "RPC IPC server started");
540            }
541            if let Some(addr) = handle.http_local_addr() {
542                info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
543            }
544            if let Some(addr) = handle.ws_local_addr() {
545                info!(target: "reth::cli", url=%addr, "RPC WS server started");
546            }
547            handle
548        });
549
550        let launch_auth = auth_module.clone().start_server(auth_config).map_ok(|handle| {
551            let addr = handle.local_addr();
552            if let Some(ipc_endpoint) = handle.ipc_endpoint() {
553                info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
554            } else {
555                info!(target: "reth::cli", url=%addr, "RPC auth server started");
556            }
557            handle
558        });
559
560        // launch servers concurrently
561        let (rpc, auth) = futures::future::try_join(launch_rpc, launch_auth).await?;
562
563        let handles = RethRpcServerHandles { rpc, auth };
564
565        let ctx = RpcContext {
566            node: node.clone(),
567            config,
568            registry: &mut registry,
569            modules: &mut modules,
570            auth_module: &mut auth_module,
571        };
572
573        on_rpc_started.on_rpc_started(ctx, handles.clone())?;
574
575        Ok(RpcHandle {
576            rpc_server_handles: handles,
577            rpc_registry: registry,
578            engine_events,
579            beacon_engine_handle,
580        })
581    }
582}
583
584impl<N, EthB, EV, EB> NodeAddOns<N> for RpcAddOns<N, EthB, EV, EB>
585where
586    N: FullNodeComponents,
587    <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
588    EthB: EthApiBuilder<N>,
589    EV: EngineValidatorBuilder<N>,
590    EB: EngineApiBuilder<N>,
591{
592    type Handle = RpcHandle<N, EthB::EthApi>;
593
594    async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
595        self.launch_add_ons_with(ctx, |_, _, _| Ok(())).await
596    }
597}
598
599/// Helper trait implemented for add-ons producing [`RpcHandle`]. Used by common node launcher
600/// implementations.
601pub trait RethRpcAddOns<N: FullNodeComponents>:
602    NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
603{
604    /// eth API implementation.
605    type EthApi: EthApiTypes;
606
607    /// Returns a mutable reference to RPC hooks.
608    fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
609}
610
611impl<N: FullNodeComponents, EthB, EV, EB> RethRpcAddOns<N> for RpcAddOns<N, EthB, EV, EB>
612where
613    Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
614    EthB: EthApiBuilder<N>,
615{
616    type EthApi = EthB::EthApi;
617
618    fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
619        &mut self.hooks
620    }
621}
622
623/// `EthApiCtx` struct
624/// This struct is used to pass the necessary context to the `EthApiBuilder` to build the `EthApi`.
625#[derive(Debug)]
626pub struct EthApiCtx<'a, N: FullNodeTypes> {
627    /// Reference to the node components
628    pub components: &'a N,
629    /// Eth API configuration
630    pub config: EthConfig,
631    /// Cache for eth state
632    pub cache: EthStateCache<BlockTy<N::Types>, ReceiptTy<N::Types>>,
633}
634
635/// A `EthApi` that knows how to build `eth` namespace API from [`FullNodeComponents`].
636pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
637    /// The Ethapi implementation this builder will build.
638    type EthApi: EthApiTypes
639        + FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
640        + AddDevSigners
641        + Unpin
642        + 'static;
643
644    /// Builds the [`EthApiServer`](reth_rpc_api::eth::EthApiServer) from the given context.
645    fn build_eth_api(
646        self,
647        ctx: EthApiCtx<'_, N>,
648    ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
649}
650
651/// Helper trait that provides the validator for the engine API
652pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
653    /// The Validator type to use for the engine API.
654    type Validator: EngineValidator<<Node::Types as NodeTypes>::Payload, Block = BlockTy<Node::Types>>
655        + Clone;
656
657    /// Creates the engine validator for an engine API based node.
658    fn engine_validator(
659        &self,
660        ctx: &AddOnsContext<'_, Node>,
661    ) -> impl Future<Output = eyre::Result<Self::Validator>>;
662}
663
664impl<N, EthB, EV, EB> EngineValidatorAddOn<N> for RpcAddOns<N, EthB, EV, EB>
665where
666    N: FullNodeComponents,
667    EthB: EthApiBuilder<N>,
668    EV: EngineValidatorBuilder<N>,
669    EB: EngineApiBuilder<N>,
670{
671    type Validator = EV::Validator;
672
673    async fn engine_validator(&self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::Validator> {
674        self.engine_validator_builder.clone().build(ctx).await
675    }
676}
677
678/// A type that knows how to build the engine validator.
679pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
680    /// The consensus implementation to build.
681    type Validator: EngineValidator<<Node::Types as NodeTypes>::Payload, Block = BlockTy<Node::Types>>
682        + Clone;
683
684    /// Creates the engine validator.
685    fn build(
686        self,
687        ctx: &AddOnsContext<'_, Node>,
688    ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
689}
690
691impl<Node, F, Fut, Validator> EngineValidatorBuilder<Node> for F
692where
693    Node: FullNodeComponents,
694    Validator: EngineValidator<<Node::Types as NodeTypes>::Payload, Block = BlockTy<Node::Types>>
695        + Clone
696        + Unpin
697        + 'static,
698    F: FnOnce(&AddOnsContext<'_, Node>) -> Fut + Send + Sync + Clone,
699    Fut: Future<Output = eyre::Result<Validator>> + Send,
700{
701    type Validator = Validator;
702
703    fn build(
704        self,
705        ctx: &AddOnsContext<'_, Node>,
706    ) -> impl Future<Output = eyre::Result<Self::Validator>> {
707        self(ctx)
708    }
709}
710
711/// Builder for engine API RPC module.
712///
713/// This builder type is responsible for providing an instance of [`IntoEngineApiRpcModule`], which
714/// is effectively a helper trait that provides the type erased [`jsonrpsee::RpcModule`] instance
715/// that contains the method handlers for the engine API. See [`EngineApi`] for an implementation of
716/// [`IntoEngineApiRpcModule`].
717pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
718    /// The engine API RPC module. Only required to be convertible to an [`jsonrpsee::RpcModule`].
719    type EngineApi: IntoEngineApiRpcModule + Send + Sync;
720
721    /// Builds the engine API instance given the provided [`AddOnsContext`].
722    ///
723    /// [`Self::EngineApi`] will be converted into the method handlers of the authenticated RPC
724    /// server (engine API).
725    fn build_engine_api(
726        self,
727        ctx: &AddOnsContext<'_, Node>,
728    ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
729}
730
731/// Builder for basic [`EngineApi`] implementation.
732///
733/// This provides a basic default implementation for opstack and ethereum engine API via
734/// [`EngineTypes`] and uses the general purpose [`EngineApi`] implementation as the builder's
735/// output.
736#[derive(Debug, Default)]
737pub struct BasicEngineApiBuilder<EV> {
738    engine_validator_builder: EV,
739}
740
741impl<N, EV> EngineApiBuilder<N> for BasicEngineApiBuilder<EV>
742where
743    N: FullNodeComponents<
744        Types: NodeTypes<
745            ChainSpec: EthereumHardforks,
746            Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
747        >,
748    >,
749    EV: EngineValidatorBuilder<N>,
750{
751    type EngineApi = EngineApi<
752        N::Provider,
753        <N::Types as NodeTypes>::Payload,
754        N::Pool,
755        EV::Validator,
756        <N::Types as NodeTypes>::ChainSpec,
757    >;
758
759    async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
760        let Self { engine_validator_builder } = self;
761
762        let engine_validator = engine_validator_builder.build(ctx).await?;
763        let client = ClientVersionV1 {
764            code: CLIENT_CODE,
765            name: NAME_CLIENT.to_string(),
766            version: CARGO_PKG_VERSION.to_string(),
767            commit: VERGEN_GIT_SHA.to_string(),
768        };
769        Ok(EngineApi::new(
770            ctx.node.provider().clone(),
771            ctx.config.chain.clone(),
772            ctx.beacon_engine_handle.clone(),
773            PayloadStore::new(ctx.node.payload_builder_handle().clone()),
774            ctx.node.pool().clone(),
775            Box::new(ctx.node.task_executor().clone()),
776            client,
777            EngineCapabilities::default(),
778            engine_validator,
779            ctx.config.engine.accept_execution_requests_hash,
780        ))
781    }
782}
783
784/// A noop Builder that satisfies the [`EngineApiBuilder`] trait without actually configuring an
785/// engine API module
786///
787/// This is intended to be used as a workaround for reusing all the existing ethereum node launch
788/// utilities which require an engine API.
789#[derive(Debug, Clone, Default)]
790#[non_exhaustive]
791pub struct NoopEngineApiBuilder;
792
793impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
794    type EngineApi = NoopEngineApi;
795
796    async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
797        Ok(NoopEngineApi::default())
798    }
799}
800
801/// Represents an empty Engine API [`RpcModule`].
802///
803/// This is only intended to be used in combination with the [`NoopEngineApiBuilder`] in order to
804/// satisfy trait bounds in the regular ethereum launch routine that mandate an engine API instance.
805#[derive(Debug, Clone, Default)]
806#[non_exhaustive]
807pub struct NoopEngineApi;
808
809impl IntoEngineApiRpcModule for NoopEngineApi {
810    fn into_rpc_module(self) -> RpcModule<()> {
811        RpcModule::new(())
812    }
813}