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::{
27 eth::{core::EthRpcConverterFor, DevSigner, EthApiTypes, FullEthApiServer},
28 AdminApi,
29};
30use reth_rpc_api::{eth::helpers::EthTransactions, IntoEngineApiRpcModule};
31use reth_rpc_builder::{
32 auth::{AuthRpcModule, AuthServerHandle},
33 config::RethRpcServerConfig,
34 RpcModuleBuilder, RpcRegistryInner, RpcServerConfig, RpcServerHandle, TransportRpcModules,
35};
36use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
37use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
38use reth_tokio_util::EventSender;
39use reth_tracing::tracing::{debug, info};
40use std::{
41 fmt::{self, Debug},
42 future::Future,
43 ops::{Deref, DerefMut},
44};
45
46#[derive(Debug, Clone)]
50pub struct RethRpcServerHandles {
51 pub rpc: RpcServerHandle,
53 pub auth: AuthServerHandle,
55}
56
57pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
59 pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
61 pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
63}
64
65impl<Node, EthApi> Default for RpcHooks<Node, EthApi>
66where
67 Node: FullNodeComponents,
68 EthApi: EthApiTypes,
69{
70 fn default() -> Self {
71 Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
72 }
73}
74
75impl<Node, EthApi> RpcHooks<Node, EthApi>
76where
77 Node: FullNodeComponents,
78 EthApi: EthApiTypes,
79{
80 pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
82 where
83 F: OnRpcStarted<Node, EthApi> + 'static,
84 {
85 self.on_rpc_started = Box::new(hook);
86 self
87 }
88
89 #[expect(unused)]
91 pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
92 where
93 F: OnRpcStarted<Node, EthApi> + 'static,
94 {
95 self.set_on_rpc_started(hook);
96 self
97 }
98
99 pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
101 where
102 F: ExtendRpcModules<Node, EthApi> + 'static,
103 {
104 self.extend_rpc_modules = Box::new(hook);
105 self
106 }
107
108 #[expect(unused)]
110 pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
111 where
112 F: ExtendRpcModules<Node, EthApi> + 'static,
113 {
114 self.set_extend_rpc_modules(hook);
115 self
116 }
117}
118
119impl<Node, EthApi> fmt::Debug for RpcHooks<Node, EthApi>
120where
121 Node: FullNodeComponents,
122 EthApi: EthApiTypes,
123{
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.debug_struct("RpcHooks")
126 .field("on_rpc_started", &"...")
127 .field("extend_rpc_modules", &"...")
128 .finish()
129 }
130}
131
132pub trait OnRpcStarted<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
134 fn on_rpc_started(
136 self: Box<Self>,
137 ctx: RpcContext<'_, Node, EthApi>,
138 handles: RethRpcServerHandles,
139 ) -> eyre::Result<()>;
140}
141
142impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
143where
144 F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
145 Node: FullNodeComponents,
146 EthApi: EthApiTypes,
147{
148 fn on_rpc_started(
149 self: Box<Self>,
150 ctx: RpcContext<'_, Node, EthApi>,
151 handles: RethRpcServerHandles,
152 ) -> eyre::Result<()> {
153 (*self)(ctx, handles)
154 }
155}
156
157impl<Node, EthApi> OnRpcStarted<Node, EthApi> for ()
158where
159 Node: FullNodeComponents,
160 EthApi: EthApiTypes,
161{
162 fn on_rpc_started(
163 self: Box<Self>,
164 _: RpcContext<'_, Node, EthApi>,
165 _: RethRpcServerHandles,
166 ) -> eyre::Result<()> {
167 Ok(())
168 }
169}
170
171pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
173 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
175}
176
177impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
178where
179 F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
180 Node: FullNodeComponents,
181 EthApi: EthApiTypes,
182{
183 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
184 (*self)(ctx)
185 }
186}
187
188impl<Node, EthApi> ExtendRpcModules<Node, EthApi> for ()
189where
190 Node: FullNodeComponents,
191 EthApi: EthApiTypes,
192{
193 fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
194 Ok(())
195 }
196}
197
198#[derive(Debug, Clone)]
200#[expect(clippy::type_complexity)]
201pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
202 pub(crate) registry: RpcRegistryInner<
203 Node::Provider,
204 Node::Pool,
205 Node::Network,
206 EthApi,
207 Node::Evm,
208 Node::Consensus,
209 >,
210}
211
212impl<Node, EthApi> Deref for RpcRegistry<Node, EthApi>
213where
214 Node: FullNodeComponents,
215 EthApi: EthApiTypes,
216{
217 type Target = RpcRegistryInner<
218 Node::Provider,
219 Node::Pool,
220 Node::Network,
221 EthApi,
222 Node::Evm,
223 Node::Consensus,
224 >;
225
226 fn deref(&self) -> &Self::Target {
227 &self.registry
228 }
229}
230
231impl<Node, EthApi> DerefMut for RpcRegistry<Node, EthApi>
232where
233 Node: FullNodeComponents,
234 EthApi: EthApiTypes,
235{
236 fn deref_mut(&mut self) -> &mut Self::Target {
237 &mut self.registry
238 }
239}
240
241#[expect(missing_debug_implementations)]
243pub struct RpcModuleContainer<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
244 pub modules: &'a mut TransportRpcModules,
246 pub auth_module: &'a mut AuthRpcModule,
248 pub registry: &'a mut RpcRegistry<Node, EthApi>,
250}
251
252#[expect(missing_debug_implementations)]
260pub struct RpcContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
261 pub(crate) node: Node,
263
264 pub(crate) config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
266
267 pub registry: &'a mut RpcRegistry<Node, EthApi>,
271 pub modules: &'a mut TransportRpcModules,
276 pub auth_module: &'a mut AuthRpcModule,
280}
281
282impl<Node, EthApi> RpcContext<'_, Node, EthApi>
283where
284 Node: FullNodeComponents,
285 EthApi: EthApiTypes,
286{
287 pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
289 self.config
290 }
291
292 pub const fn node(&self) -> &Node {
296 &self.node
297 }
298
299 pub fn pool(&self) -> &Node::Pool {
301 self.node.pool()
302 }
303
304 pub fn provider(&self) -> &Node::Provider {
306 self.node.provider()
307 }
308
309 pub fn network(&self) -> &Node::Network {
311 self.node.network()
312 }
313
314 pub fn payload_builder_handle(
316 &self,
317 ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
318 self.node.payload_builder_handle()
319 }
320}
321
322pub struct RpcHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
324 pub rpc_server_handles: RethRpcServerHandles,
326 pub rpc_registry: RpcRegistry<Node, EthApi>,
328 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
333 pub beacon_engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
335}
336
337impl<Node: FullNodeComponents, EthApi: EthApiTypes> Clone for RpcHandle<Node, EthApi> {
338 fn clone(&self) -> Self {
339 Self {
340 rpc_server_handles: self.rpc_server_handles.clone(),
341 rpc_registry: self.rpc_registry.clone(),
342 engine_events: self.engine_events.clone(),
343 beacon_engine_handle: self.beacon_engine_handle.clone(),
344 }
345 }
346}
347
348impl<Node: FullNodeComponents, EthApi: EthApiTypes> Deref for RpcHandle<Node, EthApi> {
349 type Target = RpcRegistry<Node, EthApi>;
350
351 fn deref(&self) -> &Self::Target {
352 &self.rpc_registry
353 }
354}
355
356impl<Node: FullNodeComponents, EthApi: EthApiTypes> Debug for RpcHandle<Node, EthApi>
357where
358 RpcRegistry<Node, EthApi>: Debug,
359{
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 f.debug_struct("RpcHandle")
362 .field("rpc_server_handles", &self.rpc_server_handles)
363 .field("rpc_registry", &self.rpc_registry)
364 .finish()
365 }
366}
367
368impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcHandle<Node, EthApi> {
369 pub const fn rpc_server_handles(&self) -> &RethRpcServerHandles {
371 &self.rpc_server_handles
372 }
373
374 pub const fn consensus_engine_handle(
378 &self,
379 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
380 &self.beacon_engine_handle
381 }
382
383 pub const fn consensus_engine_events(
385 &self,
386 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
387 &self.engine_events
388 }
389
390 pub const fn eth_api(&self) -> &EthApi {
392 self.rpc_registry.registry.eth_api()
393 }
394
395 pub fn admin_api(
397 &self,
398 ) -> AdminApi<Node::Network, <Node::Types as NodeTypes>::ChainSpec, Node::Pool>
399 where
400 <Node::Types as NodeTypes>::ChainSpec: EthereumHardforks,
401 {
402 self.rpc_registry.registry.admin_api()
403 }
404}
405
406#[derive(Debug, Clone)]
412pub struct RpcServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
413 pub rpc_server_handle: RpcServerHandle,
415 pub rpc_registry: RpcRegistry<Node, EthApi>,
417 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
419 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
421}
422
423impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcServerOnlyHandle<Node, EthApi> {
424 pub const fn rpc_server_handle(&self) -> &RpcServerHandle {
426 &self.rpc_server_handle
427 }
428
429 pub const fn consensus_engine_handle(
433 &self,
434 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
435 &self.engine_handle
436 }
437
438 pub const fn consensus_engine_events(
440 &self,
441 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
442 &self.engine_events
443 }
444}
445
446#[derive(Debug, Clone)]
452pub struct AuthServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
453 pub auth_server_handle: AuthServerHandle,
455 pub rpc_registry: RpcRegistry<Node, EthApi>,
457 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
459 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
461}
462
463impl<Node: FullNodeComponents, EthApi: EthApiTypes> AuthServerOnlyHandle<Node, EthApi> {
464 pub const fn consensus_engine_handle(
468 &self,
469 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
470 &self.engine_handle
471 }
472
473 pub const fn consensus_engine_events(
475 &self,
476 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
477 &self.engine_events
478 }
479}
480
481struct RpcSetupContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
483 node: Node,
484 config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
485 modules: TransportRpcModules,
486 auth_module: AuthRpcModule,
487 auth_config: reth_rpc_builder::auth::AuthServerConfig,
488 registry: RpcRegistry<Node, EthApi>,
489 on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
490 engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
491 engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
492}
493
494pub struct RpcAddOns<
505 Node: FullNodeComponents,
506 EthB: EthApiBuilder<Node>,
507 PVB,
508 EB = BasicEngineApiBuilder<PVB>,
509 EVB = BasicEngineValidatorBuilder<PVB>,
510 RpcMiddleware = Identity,
511> {
512 pub hooks: RpcHooks<Node, EthB::EthApi>,
514 eth_api_builder: EthB,
516 payload_validator_builder: PVB,
518 engine_api_builder: EB,
520 engine_validator_builder: EVB,
522 rpc_middleware: RpcMiddleware,
527 tokio_runtime: Option<tokio::runtime::Handle>,
529}
530
531impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> Debug
532 for RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
533where
534 Node: FullNodeComponents,
535 EthB: EthApiBuilder<Node>,
536 PVB: Debug,
537 EB: Debug,
538 EVB: Debug,
539{
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 f.debug_struct("RpcAddOns")
542 .field("hooks", &self.hooks)
543 .field("eth_api_builder", &"...")
544 .field("payload_validator_builder", &self.payload_validator_builder)
545 .field("engine_api_builder", &self.engine_api_builder)
546 .field("engine_validator_builder", &self.engine_validator_builder)
547 .field("rpc_middleware", &"...")
548 .finish()
549 }
550}
551
552impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
553where
554 Node: FullNodeComponents,
555 EthB: EthApiBuilder<Node>,
556{
557 pub fn new(
559 eth_api_builder: EthB,
560 payload_validator_builder: PVB,
561 engine_api_builder: EB,
562 engine_validator_builder: EVB,
563 rpc_middleware: RpcMiddleware,
564 ) -> Self {
565 Self {
566 hooks: RpcHooks::default(),
567 eth_api_builder,
568 payload_validator_builder,
569 engine_api_builder,
570 engine_validator_builder,
571 rpc_middleware,
572 tokio_runtime: None,
573 }
574 }
575
576 pub fn with_engine_api<T>(
578 self,
579 engine_api_builder: T,
580 ) -> RpcAddOns<Node, EthB, PVB, T, EVB, RpcMiddleware> {
581 let Self {
582 hooks,
583 eth_api_builder,
584 payload_validator_builder,
585 engine_validator_builder,
586 rpc_middleware,
587 tokio_runtime,
588 ..
589 } = self;
590 RpcAddOns {
591 hooks,
592 eth_api_builder,
593 payload_validator_builder,
594 engine_api_builder,
595 engine_validator_builder,
596 rpc_middleware,
597 tokio_runtime,
598 }
599 }
600
601 pub fn with_payload_validator<T>(
603 self,
604 payload_validator_builder: T,
605 ) -> RpcAddOns<Node, EthB, T, EB, EVB, RpcMiddleware> {
606 let Self {
607 hooks,
608 eth_api_builder,
609 engine_api_builder,
610 engine_validator_builder,
611 rpc_middleware,
612 tokio_runtime,
613 ..
614 } = self;
615 RpcAddOns {
616 hooks,
617 eth_api_builder,
618 payload_validator_builder,
619 engine_api_builder,
620 engine_validator_builder,
621 rpc_middleware,
622 tokio_runtime,
623 }
624 }
625
626 pub fn with_engine_validator<T>(
628 self,
629 engine_validator_builder: T,
630 ) -> RpcAddOns<Node, EthB, PVB, EB, T, RpcMiddleware> {
631 let Self {
632 hooks,
633 eth_api_builder,
634 payload_validator_builder,
635 engine_api_builder,
636 rpc_middleware,
637 tokio_runtime,
638 ..
639 } = self;
640 RpcAddOns {
641 hooks,
642 eth_api_builder,
643 payload_validator_builder,
644 engine_api_builder,
645 engine_validator_builder,
646 rpc_middleware,
647 tokio_runtime,
648 }
649 }
650
651 pub fn with_rpc_middleware<T>(
690 self,
691 rpc_middleware: T,
692 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, T> {
693 let Self {
694 hooks,
695 eth_api_builder,
696 payload_validator_builder,
697 engine_api_builder,
698 engine_validator_builder,
699 tokio_runtime,
700 ..
701 } = self;
702 RpcAddOns {
703 hooks,
704 eth_api_builder,
705 payload_validator_builder,
706 engine_api_builder,
707 engine_validator_builder,
708 rpc_middleware,
709 tokio_runtime,
710 }
711 }
712
713 pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
717 let Self {
718 hooks,
719 eth_api_builder,
720 payload_validator_builder,
721 engine_validator_builder,
722 engine_api_builder,
723 rpc_middleware,
724 ..
725 } = self;
726 Self {
727 hooks,
728 eth_api_builder,
729 payload_validator_builder,
730 engine_validator_builder,
731 engine_api_builder,
732 rpc_middleware,
733 tokio_runtime,
734 }
735 }
736
737 pub fn layer_rpc_middleware<T>(
739 self,
740 layer: T,
741 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, T>> {
742 let Self {
743 hooks,
744 eth_api_builder,
745 payload_validator_builder,
746 engine_api_builder,
747 engine_validator_builder,
748 rpc_middleware,
749 tokio_runtime,
750 } = self;
751 let rpc_middleware = Stack::new(rpc_middleware, layer);
752 RpcAddOns {
753 hooks,
754 eth_api_builder,
755 payload_validator_builder,
756 engine_api_builder,
757 engine_validator_builder,
758 rpc_middleware,
759 tokio_runtime,
760 }
761 }
762
763 #[expect(clippy::type_complexity)]
765 pub fn option_layer_rpc_middleware<T>(
766 self,
767 layer: Option<T>,
768 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, Either<T, Identity>>> {
769 let layer = layer.map(Either::Left).unwrap_or(Either::Right(Identity::new()));
770 self.layer_rpc_middleware(layer)
771 }
772
773 pub fn on_rpc_started<F>(mut self, hook: F) -> Self
775 where
776 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>, RethRpcServerHandles) -> eyre::Result<()>
777 + Send
778 + 'static,
779 {
780 self.hooks.set_on_rpc_started(hook);
781 self
782 }
783
784 pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
786 where
787 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>) -> eyre::Result<()> + Send + 'static,
788 {
789 self.hooks.set_extend_rpc_modules(hook);
790 self
791 }
792}
793
794impl<Node, EthB, EV, EB, Engine> Default for RpcAddOns<Node, EthB, EV, EB, Engine, Identity>
795where
796 Node: FullNodeComponents,
797 EthB: EthApiBuilder<Node>,
798 EV: Default,
799 EB: Default,
800 Engine: Default,
801{
802 fn default() -> Self {
803 Self::new(
804 EthB::default(),
805 EV::default(),
806 EB::default(),
807 Engine::default(),
808 Default::default(),
809 )
810 }
811}
812
813impl<N, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
814where
815 N: FullNodeComponents,
816 N::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
817 EthB: EthApiBuilder<N>,
818 EB: EngineApiBuilder<N>,
819 EVB: EngineValidatorBuilder<N>,
820 RpcMiddleware: RethRpcMiddleware,
821{
822 pub async fn launch_rpc_server<F>(
828 self,
829 ctx: AddOnsContext<'_, N>,
830 ext: F,
831 ) -> eyre::Result<RpcServerOnlyHandle<N, EthB::EthApi>>
832 where
833 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
834 {
835 let rpc_middleware = self.rpc_middleware.clone();
836 let tokio_runtime = self.tokio_runtime.clone();
837 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
838 let RpcSetupContext {
839 node,
840 config,
841 mut modules,
842 mut auth_module,
843 auth_config: _,
844 mut registry,
845 on_rpc_started,
846 engine_events,
847 engine_handle,
848 } = setup_ctx;
849
850 let server_config = config
851 .rpc
852 .rpc_server_config()
853 .set_rpc_middleware(rpc_middleware)
854 .with_tokio_runtime(tokio_runtime);
855 let rpc_server_handle = Self::launch_rpc_server_internal(server_config, &modules).await?;
856
857 let handles =
858 RethRpcServerHandles { rpc: rpc_server_handle.clone(), auth: AuthServerHandle::noop() };
859 Self::finalize_rpc_setup(
860 &mut registry,
861 &mut modules,
862 &mut auth_module,
863 &node,
864 config,
865 on_rpc_started,
866 handles,
867 )?;
868
869 Ok(RpcServerOnlyHandle {
870 rpc_server_handle,
871 rpc_registry: registry,
872 engine_events,
873 engine_handle,
874 })
875 }
876
877 pub async fn launch_add_ons_with<F>(
880 self,
881 ctx: AddOnsContext<'_, N>,
882 ext: F,
883 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
884 where
885 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
886 {
887 let disable_auth = ctx.config.rpc.disable_auth_server;
889 self.launch_add_ons_with_opt_engine(ctx, ext, disable_auth).await
890 }
891
892 pub async fn launch_add_ons_with_opt_engine<F>(
898 self,
899 ctx: AddOnsContext<'_, N>,
900 ext: F,
901 disable_auth: bool,
902 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
903 where
904 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
905 {
906 let rpc_middleware = self.rpc_middleware.clone();
907 let tokio_runtime = self.tokio_runtime.clone();
908 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
909 let RpcSetupContext {
910 node,
911 config,
912 mut modules,
913 mut auth_module,
914 auth_config,
915 mut registry,
916 on_rpc_started,
917 engine_events,
918 engine_handle,
919 } = setup_ctx;
920
921 let server_config = config
922 .rpc
923 .rpc_server_config()
924 .set_rpc_middleware(rpc_middleware)
925 .with_tokio_runtime(tokio_runtime);
926
927 let (rpc, auth) = if disable_auth {
928 let rpc = Self::launch_rpc_server_internal(server_config, &modules).await?;
930 (rpc, AuthServerHandle::noop())
931 } else {
932 let auth_module_clone = auth_module.clone();
933 let (rpc, auth) = futures::future::try_join(
935 Self::launch_rpc_server_internal(server_config, &modules),
936 Self::launch_auth_server_internal(auth_module_clone, auth_config),
937 )
938 .await?;
939 (rpc, auth)
940 };
941
942 let handles = RethRpcServerHandles { rpc, auth };
943
944 Self::finalize_rpc_setup(
945 &mut registry,
946 &mut modules,
947 &mut auth_module,
948 &node,
949 config,
950 on_rpc_started,
951 handles.clone(),
952 )?;
953
954 Ok(RpcHandle {
955 rpc_server_handles: handles,
956 rpc_registry: registry,
957 engine_events,
958 beacon_engine_handle: engine_handle,
959 })
960 }
961
962 async fn setup_rpc_components<'a, F>(
964 self,
965 ctx: AddOnsContext<'a, N>,
966 ext: F,
967 ) -> eyre::Result<RpcSetupContext<'a, N, EthB::EthApi>>
968 where
969 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
970 {
971 let Self { eth_api_builder, engine_api_builder, hooks, .. } = self;
972
973 let engine_api = engine_api_builder.build_engine_api(&ctx).await?;
974 let AddOnsContext { node, config, beacon_engine_handle, jwt_secret, engine_events } = ctx;
975
976 info!(target: "reth::cli", "Engine API handler initialized");
977
978 let cache = EthStateCache::spawn_with(
979 node.provider().clone(),
980 config.rpc.eth_config().cache,
981 node.task_executor().clone(),
982 );
983
984 let new_canonical_blocks = node.provider().canonical_state_stream();
985 let c = cache.clone();
986 node.task_executor().spawn_critical(
987 "cache canonical blocks task",
988 Box::pin(async move {
989 cache_new_blocks_task(c, new_canonical_blocks).await;
990 }),
991 );
992
993 let eth_config = config.rpc.eth_config().max_batch_size(config.txpool.max_batch_size());
994 let ctx = EthApiCtx {
995 components: &node,
996 config: eth_config,
997 cache,
998 engine_handle: beacon_engine_handle.clone(),
999 };
1000 let eth_api = eth_api_builder.build_eth_api(ctx).await?;
1001
1002 let auth_config = config.rpc.auth_server_config(jwt_secret)?;
1003 let module_config = config.rpc.transport_rpc_module_config();
1004 debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config");
1005
1006 let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
1007 .with_provider(node.provider().clone())
1008 .with_pool(node.pool().clone())
1009 .with_network(node.network().clone())
1010 .with_executor(Box::new(node.task_executor().clone()))
1011 .with_evm_config(node.evm_config().clone())
1012 .with_consensus(node.consensus().clone())
1013 .build_with_auth_server(module_config, engine_api, eth_api);
1014
1015 if config.dev.dev {
1017 let signers = DevSigner::from_mnemonic(config.dev.dev_mnemonic.as_str(), 20);
1018 registry.eth_api().signers().write().extend(signers);
1019 }
1020
1021 let mut registry = RpcRegistry { registry };
1022 let ctx = RpcContext {
1023 node: node.clone(),
1024 config,
1025 registry: &mut registry,
1026 modules: &mut modules,
1027 auth_module: &mut auth_module,
1028 };
1029
1030 let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
1031
1032 ext(RpcModuleContainer {
1033 modules: ctx.modules,
1034 auth_module: ctx.auth_module,
1035 registry: ctx.registry,
1036 })?;
1037 extend_rpc_modules.extend_rpc_modules(ctx)?;
1038
1039 Ok(RpcSetupContext {
1040 node,
1041 config,
1042 modules,
1043 auth_module,
1044 auth_config,
1045 registry,
1046 on_rpc_started,
1047 engine_events,
1048 engine_handle: beacon_engine_handle,
1049 })
1050 }
1051
1052 async fn launch_rpc_server_internal<M>(
1054 server_config: RpcServerConfig<M>,
1055 modules: &TransportRpcModules,
1056 ) -> eyre::Result<RpcServerHandle>
1057 where
1058 M: RethRpcMiddleware,
1059 {
1060 let handle = server_config.start(modules).await?;
1061
1062 if let Some(path) = handle.ipc_endpoint() {
1063 info!(target: "reth::cli", %path, "RPC IPC server started");
1064 }
1065 if let Some(addr) = handle.http_local_addr() {
1066 info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
1067 }
1068 if let Some(addr) = handle.ws_local_addr() {
1069 info!(target: "reth::cli", url=%addr, "RPC WS server started");
1070 }
1071
1072 Ok(handle)
1073 }
1074
1075 async fn launch_auth_server_internal(
1077 auth_module: AuthRpcModule,
1078 auth_config: reth_rpc_builder::auth::AuthServerConfig,
1079 ) -> eyre::Result<AuthServerHandle> {
1080 auth_module.start_server(auth_config)
1081 .await
1082 .map_err(Into::into)
1083 .inspect(|handle| {
1084 let addr = handle.local_addr();
1085 if let Some(ipc_endpoint) = handle.ipc_endpoint() {
1086 info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
1087 } else {
1088 info!(target: "reth::cli", url=%addr, "RPC auth server started");
1089 }
1090 })
1091 }
1092
1093 fn finalize_rpc_setup(
1095 registry: &mut RpcRegistry<N, EthB::EthApi>,
1096 modules: &mut TransportRpcModules,
1097 auth_module: &mut AuthRpcModule,
1098 node: &N,
1099 config: &NodeConfig<<N::Types as NodeTypes>::ChainSpec>,
1100 on_rpc_started: Box<dyn OnRpcStarted<N, EthB::EthApi>>,
1101 handles: RethRpcServerHandles,
1102 ) -> eyre::Result<()> {
1103 let ctx = RpcContext { node: node.clone(), config, registry, modules, auth_module };
1104
1105 on_rpc_started.on_rpc_started(ctx, handles)?;
1106 Ok(())
1107 }
1108}
1109
1110impl<N, EthB, PVB, EB, EVB, RpcMiddleware> NodeAddOns<N>
1111 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1112where
1113 N: FullNodeComponents,
1114 <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
1115 EthB: EthApiBuilder<N>,
1116 PVB: PayloadValidatorBuilder<N>,
1117 EB: EngineApiBuilder<N>,
1118 EVB: EngineValidatorBuilder<N>,
1119 RpcMiddleware: RethRpcMiddleware,
1120{
1121 type Handle = RpcHandle<N, EthB::EthApi>;
1122
1123 async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
1124 self.launch_add_ons_with(ctx, |_| Ok(())).await
1125 }
1126}
1127
1128pub trait RethRpcAddOns<N: FullNodeComponents>:
1131 NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
1132{
1133 type EthApi: EthApiTypes;
1135
1136 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
1138}
1139
1140impl<N: FullNodeComponents, EthB, EV, EB, Engine, RpcMiddleware> RethRpcAddOns<N>
1141 for RpcAddOns<N, EthB, EV, EB, Engine, RpcMiddleware>
1142where
1143 Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
1144 EthB: EthApiBuilder<N>,
1145{
1146 type EthApi = EthB::EthApi;
1147
1148 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
1149 &mut self.hooks
1150 }
1151}
1152
1153#[derive(Debug)]
1156pub struct EthApiCtx<'a, N: FullNodeTypes> {
1157 pub components: &'a N,
1159 pub config: EthConfig,
1161 pub cache: EthStateCache<PrimitivesTy<N::Types>>,
1163 pub engine_handle: ConsensusEngineHandle<<N::Types as NodeTypes>::Payload>,
1165}
1166
1167impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>>>
1168 EthApiCtx<'a, N>
1169{
1170 pub fn eth_api_builder(self) -> reth_rpc::EthApiBuilder<N, EthRpcConverterFor<N>> {
1172 reth_rpc::EthApiBuilder::new_with_components(self.components.clone())
1173 .eth_cache(self.cache)
1174 .task_spawner(self.components.task_executor().clone())
1175 .gas_cap(self.config.rpc_gas_cap.into())
1176 .max_simulate_blocks(self.config.rpc_max_simulate_blocks)
1177 .eth_proof_window(self.config.eth_proof_window)
1178 .fee_history_cache_config(self.config.fee_history_cache)
1179 .proof_permits(self.config.proof_permits)
1180 .gas_oracle_config(self.config.gas_oracle)
1181 .max_batch_size(self.config.max_batch_size)
1182 .pending_block_kind(self.config.pending_block_kind)
1183 .raw_tx_forwarder(self.config.raw_tx_forwarder)
1184 .evm_memory_limit(self.config.rpc_evm_memory_limit)
1185 }
1186}
1187
1188pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
1190 type EthApi: EthApiTypes
1192 + FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
1193 + Unpin
1194 + 'static;
1195
1196 fn build_eth_api(
1198 self,
1199 ctx: EthApiCtx<'_, N>,
1200 ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
1201}
1202
1203pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
1205 type ValidatorBuilder: EngineValidatorBuilder<Node>;
1207
1208 fn engine_validator_builder(&self) -> Self::ValidatorBuilder;
1210}
1211
1212impl<N, EthB, PVB, EB, EVB, RpcMiddleware> EngineValidatorAddOn<N>
1213 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1214where
1215 N: FullNodeComponents,
1216 EthB: EthApiBuilder<N>,
1217 PVB: Send,
1218 EB: EngineApiBuilder<N>,
1219 EVB: EngineValidatorBuilder<N>,
1220 RpcMiddleware: Send,
1221{
1222 type ValidatorBuilder = EVB;
1223
1224 fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
1225 self.engine_validator_builder.clone()
1226 }
1227}
1228
1229pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
1236 type EngineApi: IntoEngineApiRpcModule + Send + Sync;
1238
1239 fn build_engine_api(
1244 self,
1245 ctx: &AddOnsContext<'_, Node>,
1246 ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
1247}
1248
1249pub trait PayloadValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1254 type Validator: PayloadValidator<<Node::Types as NodeTypes>::Payload>;
1256
1257 fn build(
1262 self,
1263 ctx: &AddOnsContext<'_, Node>,
1264 ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
1265}
1266
1267pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1272 type EngineValidator: EngineValidator<
1274 <Node::Types as NodeTypes>::Payload,
1275 <Node::Types as NodeTypes>::Primitives,
1276 >;
1277
1278 fn build_tree_validator(
1282 self,
1283 ctx: &AddOnsContext<'_, Node>,
1284 tree_config: TreeConfig,
1285 ) -> impl Future<Output = eyre::Result<Self::EngineValidator>> + Send;
1286}
1287
1288#[derive(Debug, Clone)]
1292pub struct BasicEngineValidatorBuilder<EV> {
1293 payload_validator_builder: EV,
1295}
1296
1297impl<EV> BasicEngineValidatorBuilder<EV> {
1298 pub const fn new(payload_validator_builder: EV) -> Self {
1300 Self { payload_validator_builder }
1301 }
1302}
1303
1304impl<EV> Default for BasicEngineValidatorBuilder<EV>
1305where
1306 EV: Default,
1307{
1308 fn default() -> Self {
1309 Self::new(EV::default())
1310 }
1311}
1312
1313impl<Node, EV> EngineValidatorBuilder<Node> for BasicEngineValidatorBuilder<EV>
1314where
1315 Node: FullNodeComponents<
1316 Evm: ConfigureEngineEvm<
1317 <<Node::Types as NodeTypes>::Payload as PayloadTypes>::ExecutionData,
1318 >,
1319 >,
1320 EV: PayloadValidatorBuilder<Node>,
1321 EV::Validator: reth_engine_primitives::PayloadValidator<
1322 <Node::Types as NodeTypes>::Payload,
1323 Block = BlockTy<Node::Types>,
1324 >,
1325{
1326 type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
1327
1328 async fn build_tree_validator(
1329 self,
1330 ctx: &AddOnsContext<'_, Node>,
1331 tree_config: TreeConfig,
1332 ) -> eyre::Result<Self::EngineValidator> {
1333 let validator = self.payload_validator_builder.build(ctx).await?;
1334 let data_dir = ctx.config.datadir.clone().resolve_datadir(ctx.config.chain.chain());
1335 let invalid_block_hook = ctx.create_invalid_block_hook(&data_dir).await?;
1336 Ok(BasicEngineValidator::new(
1337 ctx.node.provider().clone(),
1338 std::sync::Arc::new(ctx.node.consensus().clone()),
1339 ctx.node.evm_config().clone(),
1340 validator,
1341 tree_config,
1342 invalid_block_hook,
1343 ))
1344 }
1345}
1346
1347#[derive(Debug, Default)]
1353pub struct BasicEngineApiBuilder<PVB> {
1354 payload_validator_builder: PVB,
1355}
1356
1357impl<N, PVB> EngineApiBuilder<N> for BasicEngineApiBuilder<PVB>
1358where
1359 N: FullNodeComponents<
1360 Types: NodeTypes<
1361 ChainSpec: EthereumHardforks,
1362 Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
1363 >,
1364 >,
1365 PVB: PayloadValidatorBuilder<N>,
1366 PVB::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
1367{
1368 type EngineApi = EngineApi<
1369 N::Provider,
1370 <N::Types as NodeTypes>::Payload,
1371 N::Pool,
1372 PVB::Validator,
1373 <N::Types as NodeTypes>::ChainSpec,
1374 >;
1375
1376 async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1377 let Self { payload_validator_builder } = self;
1378
1379 let engine_validator = payload_validator_builder.build(ctx).await?;
1380 let client = ClientVersionV1 {
1381 code: CLIENT_CODE,
1382 name: version_metadata().name_client.to_string(),
1383 version: version_metadata().cargo_pkg_version.to_string(),
1384 commit: version_metadata().vergen_git_sha.to_string(),
1385 };
1386 Ok(EngineApi::new(
1387 ctx.node.provider().clone(),
1388 ctx.config.chain.clone(),
1389 ctx.beacon_engine_handle.clone(),
1390 PayloadStore::new(ctx.node.payload_builder_handle().clone()),
1391 ctx.node.pool().clone(),
1392 Box::new(ctx.node.task_executor().clone()),
1393 client,
1394 EngineCapabilities::default(),
1395 engine_validator,
1396 ctx.config.engine.accept_execution_requests_hash,
1397 ))
1398 }
1399}
1400
1401#[derive(Debug, Clone, Default)]
1407#[non_exhaustive]
1408pub struct NoopEngineApiBuilder;
1409
1410impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
1411 type EngineApi = NoopEngineApi;
1412
1413 async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1414 Ok(NoopEngineApi::default())
1415 }
1416}
1417
1418#[derive(Debug, Clone, Default)]
1423#[non_exhaustive]
1424pub struct NoopEngineApi;
1425
1426impl IntoEngineApiRpcModule for NoopEngineApi {
1427 fn into_rpc_module(self) -> RpcModule<()> {
1428 RpcModule::new(())
1429 }
1430}