1pub use jsonrpsee::server::middleware::rpc::{RpcService, RpcServiceBuilder};
4pub use reth_engine_tree::tree::{BasicEngineValidator, EngineValidator};
5pub use reth_rpc_builder::{middleware::RethRpcMiddleware, Identity, Stack};
6
7use crate::{
8 invalid_block_hook::InvalidBlockHookExt, ConfigureEngineEvm, ConsensusEngineEvent,
9 ConsensusEngineHandle,
10};
11use alloy_rpc_types::engine::ClientVersionV1;
12use alloy_rpc_types_engine::ExecutionData;
13use jsonrpsee::{core::middleware::layer::Either, RpcModule};
14use reth_chain_state::CanonStateSubscriptions;
15use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks, Hardforks};
16use reth_node_api::{
17 AddOnsContext, BlockTy, EngineApiValidator, EngineTypes, FullNodeComponents, FullNodeTypes,
18 NodeAddOns, NodeTypes, PayloadTypes, PayloadValidator, PrimitivesTy, TreeConfig,
19};
20use reth_node_core::{
21 cli::config::RethTransactionPoolConfig,
22 node_config::NodeConfig,
23 version::{version_metadata, CLIENT_CODE},
24};
25use reth_payload_builder::{PayloadBuilderHandle, PayloadStore};
26use reth_rpc::eth::{core::EthRpcConverterFor, EthApiTypes, FullEthApiServer};
27use reth_rpc_api::{eth::helpers::AddDevSigners, IntoEngineApiRpcModule};
28use reth_rpc_builder::{
29 auth::{AuthRpcModule, AuthServerHandle},
30 config::RethRpcServerConfig,
31 RpcModuleBuilder, RpcRegistryInner, RpcServerConfig, RpcServerHandle, TransportRpcModules,
32};
33use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
34use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
35use reth_tokio_util::EventSender;
36use reth_tracing::tracing::{debug, info};
37use std::{
38 fmt::{self, Debug},
39 future::Future,
40 ops::{Deref, DerefMut},
41};
42
43#[derive(Debug, Clone)]
47pub struct RethRpcServerHandles {
48 pub rpc: RpcServerHandle,
50 pub auth: AuthServerHandle,
52}
53
54pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
56 pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
58 pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
60}
61
62impl<Node, EthApi> Default for RpcHooks<Node, EthApi>
63where
64 Node: FullNodeComponents,
65 EthApi: EthApiTypes,
66{
67 fn default() -> Self {
68 Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
69 }
70}
71
72impl<Node, EthApi> RpcHooks<Node, EthApi>
73where
74 Node: FullNodeComponents,
75 EthApi: EthApiTypes,
76{
77 pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
79 where
80 F: OnRpcStarted<Node, EthApi> + 'static,
81 {
82 self.on_rpc_started = Box::new(hook);
83 self
84 }
85
86 #[expect(unused)]
88 pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
89 where
90 F: OnRpcStarted<Node, EthApi> + 'static,
91 {
92 self.set_on_rpc_started(hook);
93 self
94 }
95
96 pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
98 where
99 F: ExtendRpcModules<Node, EthApi> + 'static,
100 {
101 self.extend_rpc_modules = Box::new(hook);
102 self
103 }
104
105 #[expect(unused)]
107 pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
108 where
109 F: ExtendRpcModules<Node, EthApi> + 'static,
110 {
111 self.set_extend_rpc_modules(hook);
112 self
113 }
114}
115
116impl<Node, EthApi> fmt::Debug for RpcHooks<Node, EthApi>
117where
118 Node: FullNodeComponents,
119 EthApi: EthApiTypes,
120{
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("RpcHooks")
123 .field("on_rpc_started", &"...")
124 .field("extend_rpc_modules", &"...")
125 .finish()
126 }
127}
128
129pub trait OnRpcStarted<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
131 fn on_rpc_started(
133 self: Box<Self>,
134 ctx: RpcContext<'_, Node, EthApi>,
135 handles: RethRpcServerHandles,
136 ) -> eyre::Result<()>;
137}
138
139impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
140where
141 F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
142 Node: FullNodeComponents,
143 EthApi: EthApiTypes,
144{
145 fn on_rpc_started(
146 self: Box<Self>,
147 ctx: RpcContext<'_, Node, EthApi>,
148 handles: RethRpcServerHandles,
149 ) -> eyre::Result<()> {
150 (*self)(ctx, handles)
151 }
152}
153
154impl<Node, EthApi> OnRpcStarted<Node, EthApi> for ()
155where
156 Node: FullNodeComponents,
157 EthApi: EthApiTypes,
158{
159 fn on_rpc_started(
160 self: Box<Self>,
161 _: RpcContext<'_, Node, EthApi>,
162 _: RethRpcServerHandles,
163 ) -> eyre::Result<()> {
164 Ok(())
165 }
166}
167
168pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
170 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
172}
173
174impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
175where
176 F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
177 Node: FullNodeComponents,
178 EthApi: EthApiTypes,
179{
180 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
181 (*self)(ctx)
182 }
183}
184
185impl<Node, EthApi> ExtendRpcModules<Node, EthApi> for ()
186where
187 Node: FullNodeComponents,
188 EthApi: EthApiTypes,
189{
190 fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
191 Ok(())
192 }
193}
194
195#[derive(Debug, Clone)]
197#[expect(clippy::type_complexity)]
198pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
199 pub(crate) registry: RpcRegistryInner<
200 Node::Provider,
201 Node::Pool,
202 Node::Network,
203 EthApi,
204 Node::Evm,
205 Node::Consensus,
206 >,
207}
208
209impl<Node, EthApi> Deref for RpcRegistry<Node, EthApi>
210where
211 Node: FullNodeComponents,
212 EthApi: EthApiTypes,
213{
214 type Target = RpcRegistryInner<
215 Node::Provider,
216 Node::Pool,
217 Node::Network,
218 EthApi,
219 Node::Evm,
220 Node::Consensus,
221 >;
222
223 fn deref(&self) -> &Self::Target {
224 &self.registry
225 }
226}
227
228impl<Node, EthApi> DerefMut for RpcRegistry<Node, EthApi>
229where
230 Node: FullNodeComponents,
231 EthApi: EthApiTypes,
232{
233 fn deref_mut(&mut self) -> &mut Self::Target {
234 &mut self.registry
235 }
236}
237
238#[expect(missing_debug_implementations)]
240pub struct RpcModuleContainer<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
241 pub modules: &'a mut TransportRpcModules,
243 pub auth_module: &'a mut AuthRpcModule,
245 pub registry: &'a mut RpcRegistry<Node, EthApi>,
247}
248
249#[expect(missing_debug_implementations)]
257pub struct RpcContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
258 pub(crate) node: Node,
260
261 pub(crate) config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
263
264 pub registry: &'a mut RpcRegistry<Node, EthApi>,
268 pub modules: &'a mut TransportRpcModules,
273 pub auth_module: &'a mut AuthRpcModule,
277}
278
279impl<Node, EthApi> RpcContext<'_, Node, EthApi>
280where
281 Node: FullNodeComponents,
282 EthApi: EthApiTypes,
283{
284 pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
286 self.config
287 }
288
289 pub const fn node(&self) -> &Node {
293 &self.node
294 }
295
296 pub fn pool(&self) -> &Node::Pool {
298 self.node.pool()
299 }
300
301 pub fn provider(&self) -> &Node::Provider {
303 self.node.provider()
304 }
305
306 pub fn network(&self) -> &Node::Network {
308 self.node.network()
309 }
310
311 pub fn payload_builder_handle(
313 &self,
314 ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
315 self.node.payload_builder_handle()
316 }
317}
318
319pub struct RpcHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
321 pub rpc_server_handles: RethRpcServerHandles,
323 pub rpc_registry: RpcRegistry<Node, EthApi>,
325 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
330 pub beacon_engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
332}
333
334impl<Node: FullNodeComponents, EthApi: EthApiTypes> Clone for RpcHandle<Node, EthApi> {
335 fn clone(&self) -> Self {
336 Self {
337 rpc_server_handles: self.rpc_server_handles.clone(),
338 rpc_registry: self.rpc_registry.clone(),
339 engine_events: self.engine_events.clone(),
340 beacon_engine_handle: self.beacon_engine_handle.clone(),
341 }
342 }
343}
344
345impl<Node: FullNodeComponents, EthApi: EthApiTypes> Deref for RpcHandle<Node, EthApi> {
346 type Target = RpcRegistry<Node, EthApi>;
347
348 fn deref(&self) -> &Self::Target {
349 &self.rpc_registry
350 }
351}
352
353impl<Node: FullNodeComponents, EthApi: EthApiTypes> Debug for RpcHandle<Node, EthApi>
354where
355 RpcRegistry<Node, EthApi>: Debug,
356{
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 f.debug_struct("RpcHandle")
359 .field("rpc_server_handles", &self.rpc_server_handles)
360 .field("rpc_registry", &self.rpc_registry)
361 .finish()
362 }
363}
364
365impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcHandle<Node, EthApi> {
366 pub const fn rpc_server_handles(&self) -> &RethRpcServerHandles {
368 &self.rpc_server_handles
369 }
370
371 pub const fn consensus_engine_handle(
375 &self,
376 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
377 &self.beacon_engine_handle
378 }
379
380 pub const fn consensus_engine_events(
382 &self,
383 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
384 &self.engine_events
385 }
386}
387
388#[derive(Debug, Clone)]
394pub struct RpcServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
395 pub rpc_server_handle: RpcServerHandle,
397 pub rpc_registry: RpcRegistry<Node, EthApi>,
399 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
401 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
403}
404
405impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcServerOnlyHandle<Node, EthApi> {
406 pub const fn rpc_server_handle(&self) -> &RpcServerHandle {
408 &self.rpc_server_handle
409 }
410
411 pub const fn consensus_engine_handle(
415 &self,
416 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
417 &self.engine_handle
418 }
419
420 pub const fn consensus_engine_events(
422 &self,
423 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
424 &self.engine_events
425 }
426}
427
428#[derive(Debug, Clone)]
434pub struct AuthServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
435 pub auth_server_handle: AuthServerHandle,
437 pub rpc_registry: RpcRegistry<Node, EthApi>,
439 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
441 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
443}
444
445impl<Node: FullNodeComponents, EthApi: EthApiTypes> AuthServerOnlyHandle<Node, EthApi> {
446 pub const fn consensus_engine_handle(
450 &self,
451 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
452 &self.engine_handle
453 }
454
455 pub const fn consensus_engine_events(
457 &self,
458 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
459 &self.engine_events
460 }
461}
462
463struct RpcSetupContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
465 node: Node,
466 config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
467 modules: TransportRpcModules,
468 auth_module: AuthRpcModule,
469 auth_config: reth_rpc_builder::auth::AuthServerConfig,
470 registry: RpcRegistry<Node, EthApi>,
471 on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
472 engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
473 engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
474}
475
476pub struct RpcAddOns<
487 Node: FullNodeComponents,
488 EthB: EthApiBuilder<Node>,
489 PVB,
490 EB = BasicEngineApiBuilder<PVB>,
491 EVB = BasicEngineValidatorBuilder<PVB>,
492 RpcMiddleware = Identity,
493> {
494 pub hooks: RpcHooks<Node, EthB::EthApi>,
496 eth_api_builder: EthB,
498 payload_validator_builder: PVB,
500 engine_api_builder: EB,
502 engine_validator_builder: EVB,
504 rpc_middleware: RpcMiddleware,
509 tokio_runtime: Option<tokio::runtime::Handle>,
511}
512
513impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> Debug
514 for RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
515where
516 Node: FullNodeComponents,
517 EthB: EthApiBuilder<Node>,
518 PVB: Debug,
519 EB: Debug,
520 EVB: Debug,
521{
522 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
523 f.debug_struct("RpcAddOns")
524 .field("hooks", &self.hooks)
525 .field("eth_api_builder", &"...")
526 .field("payload_validator_builder", &self.payload_validator_builder)
527 .field("engine_api_builder", &self.engine_api_builder)
528 .field("engine_validator_builder", &self.engine_validator_builder)
529 .field("rpc_middleware", &"...")
530 .finish()
531 }
532}
533
534impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
535where
536 Node: FullNodeComponents,
537 EthB: EthApiBuilder<Node>,
538{
539 pub fn new(
541 eth_api_builder: EthB,
542 payload_validator_builder: PVB,
543 engine_api_builder: EB,
544 engine_validator_builder: EVB,
545 rpc_middleware: RpcMiddleware,
546 ) -> Self {
547 Self {
548 hooks: RpcHooks::default(),
549 eth_api_builder,
550 payload_validator_builder,
551 engine_api_builder,
552 engine_validator_builder,
553 rpc_middleware,
554 tokio_runtime: None,
555 }
556 }
557
558 pub fn with_engine_api<T>(
560 self,
561 engine_api_builder: T,
562 ) -> RpcAddOns<Node, EthB, PVB, T, EVB, RpcMiddleware> {
563 let Self {
564 hooks,
565 eth_api_builder,
566 payload_validator_builder,
567 engine_validator_builder,
568 rpc_middleware,
569 tokio_runtime,
570 ..
571 } = self;
572 RpcAddOns {
573 hooks,
574 eth_api_builder,
575 payload_validator_builder,
576 engine_api_builder,
577 engine_validator_builder,
578 rpc_middleware,
579 tokio_runtime,
580 }
581 }
582
583 pub fn with_payload_validator<T>(
585 self,
586 payload_validator_builder: T,
587 ) -> RpcAddOns<Node, EthB, T, EB, EVB, RpcMiddleware> {
588 let Self {
589 hooks,
590 eth_api_builder,
591 engine_api_builder,
592 engine_validator_builder,
593 rpc_middleware,
594 tokio_runtime,
595 ..
596 } = self;
597 RpcAddOns {
598 hooks,
599 eth_api_builder,
600 payload_validator_builder,
601 engine_api_builder,
602 engine_validator_builder,
603 rpc_middleware,
604 tokio_runtime,
605 }
606 }
607
608 pub fn with_engine_validator<T>(
610 self,
611 engine_validator_builder: T,
612 ) -> RpcAddOns<Node, EthB, PVB, EB, T, RpcMiddleware> {
613 let Self {
614 hooks,
615 eth_api_builder,
616 payload_validator_builder,
617 engine_api_builder,
618 rpc_middleware,
619 tokio_runtime,
620 ..
621 } = self;
622 RpcAddOns {
623 hooks,
624 eth_api_builder,
625 payload_validator_builder,
626 engine_api_builder,
627 engine_validator_builder,
628 rpc_middleware,
629 tokio_runtime,
630 }
631 }
632
633 pub fn with_rpc_middleware<T>(
672 self,
673 rpc_middleware: T,
674 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, T> {
675 let Self {
676 hooks,
677 eth_api_builder,
678 payload_validator_builder,
679 engine_api_builder,
680 engine_validator_builder,
681 tokio_runtime,
682 ..
683 } = self;
684 RpcAddOns {
685 hooks,
686 eth_api_builder,
687 payload_validator_builder,
688 engine_api_builder,
689 engine_validator_builder,
690 rpc_middleware,
691 tokio_runtime,
692 }
693 }
694
695 pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
699 let Self {
700 hooks,
701 eth_api_builder,
702 payload_validator_builder,
703 engine_validator_builder,
704 engine_api_builder,
705 rpc_middleware,
706 ..
707 } = self;
708 Self {
709 hooks,
710 eth_api_builder,
711 payload_validator_builder,
712 engine_validator_builder,
713 engine_api_builder,
714 rpc_middleware,
715 tokio_runtime,
716 }
717 }
718
719 pub fn layer_rpc_middleware<T>(
721 self,
722 layer: T,
723 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, T>> {
724 let Self {
725 hooks,
726 eth_api_builder,
727 payload_validator_builder,
728 engine_api_builder,
729 engine_validator_builder,
730 rpc_middleware,
731 tokio_runtime,
732 } = self;
733 let rpc_middleware = Stack::new(rpc_middleware, layer);
734 RpcAddOns {
735 hooks,
736 eth_api_builder,
737 payload_validator_builder,
738 engine_api_builder,
739 engine_validator_builder,
740 rpc_middleware,
741 tokio_runtime,
742 }
743 }
744
745 #[expect(clippy::type_complexity)]
747 pub fn option_layer_rpc_middleware<T>(
748 self,
749 layer: Option<T>,
750 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, Either<T, Identity>>> {
751 let layer = layer.map(Either::Left).unwrap_or(Either::Right(Identity::new()));
752 self.layer_rpc_middleware(layer)
753 }
754
755 pub fn on_rpc_started<F>(mut self, hook: F) -> Self
757 where
758 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>, RethRpcServerHandles) -> eyre::Result<()>
759 + Send
760 + 'static,
761 {
762 self.hooks.set_on_rpc_started(hook);
763 self
764 }
765
766 pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
768 where
769 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>) -> eyre::Result<()> + Send + 'static,
770 {
771 self.hooks.set_extend_rpc_modules(hook);
772 self
773 }
774}
775
776impl<Node, EthB, EV, EB, Engine> Default for RpcAddOns<Node, EthB, EV, EB, Engine, Identity>
777where
778 Node: FullNodeComponents,
779 EthB: EthApiBuilder<Node>,
780 EV: Default,
781 EB: Default,
782 Engine: Default,
783{
784 fn default() -> Self {
785 Self::new(
786 EthB::default(),
787 EV::default(),
788 EB::default(),
789 Engine::default(),
790 Default::default(),
791 )
792 }
793}
794
795impl<N, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
796where
797 N: FullNodeComponents,
798 N::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
799 EthB: EthApiBuilder<N>,
800 EB: EngineApiBuilder<N>,
801 EVB: EngineValidatorBuilder<N>,
802 RpcMiddleware: RethRpcMiddleware,
803{
804 pub async fn launch_rpc_server<F>(
810 self,
811 ctx: AddOnsContext<'_, N>,
812 ext: F,
813 ) -> eyre::Result<RpcServerOnlyHandle<N, EthB::EthApi>>
814 where
815 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
816 {
817 let rpc_middleware = self.rpc_middleware.clone();
818 let tokio_runtime = self.tokio_runtime.clone();
819 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
820 let RpcSetupContext {
821 node,
822 config,
823 mut modules,
824 mut auth_module,
825 auth_config: _,
826 mut registry,
827 on_rpc_started,
828 engine_events,
829 engine_handle,
830 } = setup_ctx;
831
832 let server_config = config
833 .rpc
834 .rpc_server_config()
835 .set_rpc_middleware(rpc_middleware)
836 .with_tokio_runtime(tokio_runtime);
837 let rpc_server_handle = Self::launch_rpc_server_internal(server_config, &modules).await?;
838
839 let handles =
840 RethRpcServerHandles { rpc: rpc_server_handle.clone(), auth: AuthServerHandle::noop() };
841 Self::finalize_rpc_setup(
842 &mut registry,
843 &mut modules,
844 &mut auth_module,
845 &node,
846 config,
847 on_rpc_started,
848 handles,
849 )?;
850
851 Ok(RpcServerOnlyHandle {
852 rpc_server_handle,
853 rpc_registry: registry,
854 engine_events,
855 engine_handle,
856 })
857 }
858
859 pub async fn launch_add_ons_with<F>(
862 self,
863 ctx: AddOnsContext<'_, N>,
864 ext: F,
865 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
866 where
867 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
868 {
869 let disable_auth = ctx.config.rpc.disable_auth_server;
871 self.launch_add_ons_with_opt_engine(ctx, ext, disable_auth).await
872 }
873
874 pub async fn launch_add_ons_with_opt_engine<F>(
880 self,
881 ctx: AddOnsContext<'_, N>,
882 ext: F,
883 disable_auth: bool,
884 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
885 where
886 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
887 {
888 let rpc_middleware = self.rpc_middleware.clone();
889 let tokio_runtime = self.tokio_runtime.clone();
890 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
891 let RpcSetupContext {
892 node,
893 config,
894 mut modules,
895 mut auth_module,
896 auth_config,
897 mut registry,
898 on_rpc_started,
899 engine_events,
900 engine_handle,
901 } = setup_ctx;
902
903 let server_config = config
904 .rpc
905 .rpc_server_config()
906 .set_rpc_middleware(rpc_middleware)
907 .with_tokio_runtime(tokio_runtime);
908
909 let (rpc, auth) = if disable_auth {
910 let rpc = Self::launch_rpc_server_internal(server_config, &modules).await?;
912 (rpc, AuthServerHandle::noop())
913 } else {
914 let auth_module_clone = auth_module.clone();
915 let (rpc, auth) = futures::future::try_join(
917 Self::launch_rpc_server_internal(server_config, &modules),
918 Self::launch_auth_server_internal(auth_module_clone, auth_config),
919 )
920 .await?;
921 (rpc, auth)
922 };
923
924 let handles = RethRpcServerHandles { rpc, auth };
925
926 Self::finalize_rpc_setup(
927 &mut registry,
928 &mut modules,
929 &mut auth_module,
930 &node,
931 config,
932 on_rpc_started,
933 handles.clone(),
934 )?;
935
936 Ok(RpcHandle {
937 rpc_server_handles: handles,
938 rpc_registry: registry,
939 engine_events,
940 beacon_engine_handle: engine_handle,
941 })
942 }
943
944 async fn setup_rpc_components<'a, F>(
946 self,
947 ctx: AddOnsContext<'a, N>,
948 ext: F,
949 ) -> eyre::Result<RpcSetupContext<'a, N, EthB::EthApi>>
950 where
951 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
952 {
953 let Self { eth_api_builder, engine_api_builder, hooks, .. } = self;
954
955 let engine_api = engine_api_builder.build_engine_api(&ctx).await?;
956 let AddOnsContext { node, config, beacon_engine_handle, jwt_secret, engine_events } = ctx;
957
958 info!(target: "reth::cli", "Engine API handler initialized");
959
960 let cache = EthStateCache::spawn_with(
961 node.provider().clone(),
962 config.rpc.eth_config().cache,
963 node.task_executor().clone(),
964 );
965
966 let new_canonical_blocks = node.provider().canonical_state_stream();
967 let c = cache.clone();
968 node.task_executor().spawn_critical(
969 "cache canonical blocks task",
970 Box::pin(async move {
971 cache_new_blocks_task(c, new_canonical_blocks).await;
972 }),
973 );
974
975 let eth_config = config.rpc.eth_config().max_batch_size(config.txpool.max_batch_size());
976 let ctx = EthApiCtx { components: &node, config: eth_config, cache };
977 let eth_api = eth_api_builder.build_eth_api(ctx).await?;
978
979 let auth_config = config.rpc.auth_server_config(jwt_secret)?;
980 let module_config = config.rpc.transport_rpc_module_config();
981 debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config");
982
983 let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
984 .with_provider(node.provider().clone())
985 .with_pool(node.pool().clone())
986 .with_network(node.network().clone())
987 .with_executor(Box::new(node.task_executor().clone()))
988 .with_evm_config(node.evm_config().clone())
989 .with_consensus(node.consensus().clone())
990 .build_with_auth_server(module_config, engine_api, eth_api);
991
992 if config.dev.dev {
994 registry.eth_api().with_dev_accounts();
995 }
996
997 let mut registry = RpcRegistry { registry };
998 let ctx = RpcContext {
999 node: node.clone(),
1000 config,
1001 registry: &mut registry,
1002 modules: &mut modules,
1003 auth_module: &mut auth_module,
1004 };
1005
1006 let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
1007
1008 ext(RpcModuleContainer {
1009 modules: ctx.modules,
1010 auth_module: ctx.auth_module,
1011 registry: ctx.registry,
1012 })?;
1013 extend_rpc_modules.extend_rpc_modules(ctx)?;
1014
1015 Ok(RpcSetupContext {
1016 node,
1017 config,
1018 modules,
1019 auth_module,
1020 auth_config,
1021 registry,
1022 on_rpc_started,
1023 engine_events,
1024 engine_handle: beacon_engine_handle,
1025 })
1026 }
1027
1028 async fn launch_rpc_server_internal<M>(
1030 server_config: RpcServerConfig<M>,
1031 modules: &TransportRpcModules,
1032 ) -> eyre::Result<RpcServerHandle>
1033 where
1034 M: RethRpcMiddleware,
1035 {
1036 let handle = server_config.start(modules).await?;
1037
1038 if let Some(path) = handle.ipc_endpoint() {
1039 info!(target: "reth::cli", %path, "RPC IPC server started");
1040 }
1041 if let Some(addr) = handle.http_local_addr() {
1042 info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
1043 }
1044 if let Some(addr) = handle.ws_local_addr() {
1045 info!(target: "reth::cli", url=%addr, "RPC WS server started");
1046 }
1047
1048 Ok(handle)
1049 }
1050
1051 async fn launch_auth_server_internal(
1053 auth_module: AuthRpcModule,
1054 auth_config: reth_rpc_builder::auth::AuthServerConfig,
1055 ) -> eyre::Result<AuthServerHandle> {
1056 auth_module.start_server(auth_config)
1057 .await
1058 .map_err(Into::into)
1059 .inspect(|handle| {
1060 let addr = handle.local_addr();
1061 if let Some(ipc_endpoint) = handle.ipc_endpoint() {
1062 info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
1063 } else {
1064 info!(target: "reth::cli", url=%addr, "RPC auth server started");
1065 }
1066 })
1067 }
1068
1069 fn finalize_rpc_setup(
1071 registry: &mut RpcRegistry<N, EthB::EthApi>,
1072 modules: &mut TransportRpcModules,
1073 auth_module: &mut AuthRpcModule,
1074 node: &N,
1075 config: &NodeConfig<<N::Types as NodeTypes>::ChainSpec>,
1076 on_rpc_started: Box<dyn OnRpcStarted<N, EthB::EthApi>>,
1077 handles: RethRpcServerHandles,
1078 ) -> eyre::Result<()> {
1079 let ctx = RpcContext { node: node.clone(), config, registry, modules, auth_module };
1080
1081 on_rpc_started.on_rpc_started(ctx, handles)?;
1082 Ok(())
1083 }
1084}
1085
1086impl<N, EthB, PVB, EB, EVB, RpcMiddleware> NodeAddOns<N>
1087 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1088where
1089 N: FullNodeComponents,
1090 <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
1091 EthB: EthApiBuilder<N>,
1092 PVB: PayloadValidatorBuilder<N>,
1093 EB: EngineApiBuilder<N>,
1094 EVB: EngineValidatorBuilder<N>,
1095 RpcMiddleware: RethRpcMiddleware,
1096{
1097 type Handle = RpcHandle<N, EthB::EthApi>;
1098
1099 async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
1100 self.launch_add_ons_with(ctx, |_| Ok(())).await
1101 }
1102}
1103
1104pub trait RethRpcAddOns<N: FullNodeComponents>:
1107 NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
1108{
1109 type EthApi: EthApiTypes;
1111
1112 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
1114}
1115
1116impl<N: FullNodeComponents, EthB, EV, EB, Engine, RpcMiddleware> RethRpcAddOns<N>
1117 for RpcAddOns<N, EthB, EV, EB, Engine, RpcMiddleware>
1118where
1119 Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
1120 EthB: EthApiBuilder<N>,
1121{
1122 type EthApi = EthB::EthApi;
1123
1124 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
1125 &mut self.hooks
1126 }
1127}
1128
1129#[derive(Debug)]
1132pub struct EthApiCtx<'a, N: FullNodeTypes> {
1133 pub components: &'a N,
1135 pub config: EthConfig,
1137 pub cache: EthStateCache<PrimitivesTy<N::Types>>,
1139}
1140
1141impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>>>
1142 EthApiCtx<'a, N>
1143{
1144 pub fn eth_api_builder(self) -> reth_rpc::EthApiBuilder<N, EthRpcConverterFor<N>> {
1146 reth_rpc::EthApiBuilder::new_with_components(self.components.clone())
1147 .eth_cache(self.cache)
1148 .task_spawner(self.components.task_executor().clone())
1149 .gas_cap(self.config.rpc_gas_cap.into())
1150 .max_simulate_blocks(self.config.rpc_max_simulate_blocks)
1151 .eth_proof_window(self.config.eth_proof_window)
1152 .fee_history_cache_config(self.config.fee_history_cache)
1153 .proof_permits(self.config.proof_permits)
1154 .gas_oracle_config(self.config.gas_oracle)
1155 .max_batch_size(self.config.max_batch_size)
1156 .pending_block_kind(self.config.pending_block_kind)
1157 .raw_tx_forwarder(self.config.raw_tx_forwarder)
1158 }
1159}
1160
1161pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
1163 type EthApi: EthApiTypes
1165 + FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
1166 + AddDevSigners
1167 + Unpin
1168 + 'static;
1169
1170 fn build_eth_api(
1172 self,
1173 ctx: EthApiCtx<'_, N>,
1174 ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
1175}
1176
1177pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
1179 type ValidatorBuilder: EngineValidatorBuilder<Node>;
1181
1182 fn engine_validator_builder(&self) -> Self::ValidatorBuilder;
1184}
1185
1186impl<N, EthB, PVB, EB, EVB, RpcMiddleware> EngineValidatorAddOn<N>
1187 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1188where
1189 N: FullNodeComponents,
1190 EthB: EthApiBuilder<N>,
1191 PVB: Send,
1192 EB: EngineApiBuilder<N>,
1193 EVB: EngineValidatorBuilder<N>,
1194 RpcMiddleware: Send,
1195{
1196 type ValidatorBuilder = EVB;
1197
1198 fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
1199 self.engine_validator_builder.clone()
1200 }
1201}
1202
1203pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
1210 type EngineApi: IntoEngineApiRpcModule + Send + Sync;
1212
1213 fn build_engine_api(
1218 self,
1219 ctx: &AddOnsContext<'_, Node>,
1220 ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
1221}
1222
1223pub trait PayloadValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1228 type Validator: PayloadValidator<<Node::Types as NodeTypes>::Payload>;
1230
1231 fn build(
1236 self,
1237 ctx: &AddOnsContext<'_, Node>,
1238 ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
1239}
1240
1241pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1246 type EngineValidator: EngineValidator<
1248 <Node::Types as NodeTypes>::Payload,
1249 <Node::Types as NodeTypes>::Primitives,
1250 >;
1251
1252 fn build_tree_validator(
1256 self,
1257 ctx: &AddOnsContext<'_, Node>,
1258 tree_config: TreeConfig,
1259 ) -> impl Future<Output = eyre::Result<Self::EngineValidator>> + Send;
1260}
1261
1262#[derive(Debug, Clone)]
1266pub struct BasicEngineValidatorBuilder<EV> {
1267 payload_validator_builder: EV,
1269}
1270
1271impl<EV> BasicEngineValidatorBuilder<EV> {
1272 pub const fn new(payload_validator_builder: EV) -> Self {
1274 Self { payload_validator_builder }
1275 }
1276}
1277
1278impl<EV> Default for BasicEngineValidatorBuilder<EV>
1279where
1280 EV: Default,
1281{
1282 fn default() -> Self {
1283 Self::new(EV::default())
1284 }
1285}
1286
1287impl<Node, EV> EngineValidatorBuilder<Node> for BasicEngineValidatorBuilder<EV>
1288where
1289 Node: FullNodeComponents<
1290 Evm: ConfigureEngineEvm<
1291 <<Node::Types as NodeTypes>::Payload as PayloadTypes>::ExecutionData,
1292 >,
1293 >,
1294 EV: PayloadValidatorBuilder<Node>,
1295 EV::Validator: reth_engine_primitives::PayloadValidator<
1296 <Node::Types as NodeTypes>::Payload,
1297 Block = BlockTy<Node::Types>,
1298 >,
1299{
1300 type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
1301
1302 async fn build_tree_validator(
1303 self,
1304 ctx: &AddOnsContext<'_, Node>,
1305 tree_config: TreeConfig,
1306 ) -> eyre::Result<Self::EngineValidator> {
1307 let validator = self.payload_validator_builder.build(ctx).await?;
1308 let data_dir = ctx.config.datadir.clone().resolve_datadir(ctx.config.chain.chain());
1309 let invalid_block_hook = ctx.create_invalid_block_hook(&data_dir).await?;
1310 Ok(BasicEngineValidator::new(
1311 ctx.node.provider().clone(),
1312 std::sync::Arc::new(ctx.node.consensus().clone()),
1313 ctx.node.evm_config().clone(),
1314 validator,
1315 tree_config,
1316 invalid_block_hook,
1317 ))
1318 }
1319}
1320
1321#[derive(Debug, Default)]
1327pub struct BasicEngineApiBuilder<PVB> {
1328 payload_validator_builder: PVB,
1329}
1330
1331impl<N, PVB> EngineApiBuilder<N> for BasicEngineApiBuilder<PVB>
1332where
1333 N: FullNodeComponents<
1334 Types: NodeTypes<
1335 ChainSpec: EthereumHardforks,
1336 Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
1337 >,
1338 >,
1339 PVB: PayloadValidatorBuilder<N>,
1340 PVB::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
1341{
1342 type EngineApi = EngineApi<
1343 N::Provider,
1344 <N::Types as NodeTypes>::Payload,
1345 N::Pool,
1346 PVB::Validator,
1347 <N::Types as NodeTypes>::ChainSpec,
1348 >;
1349
1350 async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1351 let Self { payload_validator_builder } = self;
1352
1353 let engine_validator = payload_validator_builder.build(ctx).await?;
1354 let client = ClientVersionV1 {
1355 code: CLIENT_CODE,
1356 name: version_metadata().name_client.to_string(),
1357 version: version_metadata().cargo_pkg_version.to_string(),
1358 commit: version_metadata().vergen_git_sha.to_string(),
1359 };
1360 Ok(EngineApi::new(
1361 ctx.node.provider().clone(),
1362 ctx.config.chain.clone(),
1363 ctx.beacon_engine_handle.clone(),
1364 PayloadStore::new(ctx.node.payload_builder_handle().clone()),
1365 ctx.node.pool().clone(),
1366 Box::new(ctx.node.task_executor().clone()),
1367 client,
1368 EngineCapabilities::default(),
1369 engine_validator,
1370 ctx.config.engine.accept_execution_requests_hash,
1371 ))
1372 }
1373}
1374
1375#[derive(Debug, Clone, Default)]
1381#[non_exhaustive]
1382pub struct NoopEngineApiBuilder;
1383
1384impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
1385 type EngineApi = NoopEngineApi;
1386
1387 async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1388 Ok(NoopEngineApi::default())
1389 }
1390}
1391
1392#[derive(Debug, Clone, Default)]
1397#[non_exhaustive]
1398pub struct NoopEngineApi;
1399
1400impl IntoEngineApiRpcModule for NoopEngineApi {
1401 fn into_rpc_module(self) -> RpcModule<()> {
1402 RpcModule::new(())
1403 }
1404}