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, DevSigner, EthApiTypes, FullEthApiServer};
27use reth_rpc_api::{eth::helpers::EthTransactions, 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 let signers = DevSigner::from_mnemonic(config.dev.dev_mnemonic.as_str(), 20);
995 registry.eth_api().signers().write().extend(signers);
996 }
997
998 let mut registry = RpcRegistry { registry };
999 let ctx = RpcContext {
1000 node: node.clone(),
1001 config,
1002 registry: &mut registry,
1003 modules: &mut modules,
1004 auth_module: &mut auth_module,
1005 };
1006
1007 let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
1008
1009 ext(RpcModuleContainer {
1010 modules: ctx.modules,
1011 auth_module: ctx.auth_module,
1012 registry: ctx.registry,
1013 })?;
1014 extend_rpc_modules.extend_rpc_modules(ctx)?;
1015
1016 Ok(RpcSetupContext {
1017 node,
1018 config,
1019 modules,
1020 auth_module,
1021 auth_config,
1022 registry,
1023 on_rpc_started,
1024 engine_events,
1025 engine_handle: beacon_engine_handle,
1026 })
1027 }
1028
1029 async fn launch_rpc_server_internal<M>(
1031 server_config: RpcServerConfig<M>,
1032 modules: &TransportRpcModules,
1033 ) -> eyre::Result<RpcServerHandle>
1034 where
1035 M: RethRpcMiddleware,
1036 {
1037 let handle = server_config.start(modules).await?;
1038
1039 if let Some(path) = handle.ipc_endpoint() {
1040 info!(target: "reth::cli", %path, "RPC IPC server started");
1041 }
1042 if let Some(addr) = handle.http_local_addr() {
1043 info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
1044 }
1045 if let Some(addr) = handle.ws_local_addr() {
1046 info!(target: "reth::cli", url=%addr, "RPC WS server started");
1047 }
1048
1049 Ok(handle)
1050 }
1051
1052 async fn launch_auth_server_internal(
1054 auth_module: AuthRpcModule,
1055 auth_config: reth_rpc_builder::auth::AuthServerConfig,
1056 ) -> eyre::Result<AuthServerHandle> {
1057 auth_module.start_server(auth_config)
1058 .await
1059 .map_err(Into::into)
1060 .inspect(|handle| {
1061 let addr = handle.local_addr();
1062 if let Some(ipc_endpoint) = handle.ipc_endpoint() {
1063 info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
1064 } else {
1065 info!(target: "reth::cli", url=%addr, "RPC auth server started");
1066 }
1067 })
1068 }
1069
1070 fn finalize_rpc_setup(
1072 registry: &mut RpcRegistry<N, EthB::EthApi>,
1073 modules: &mut TransportRpcModules,
1074 auth_module: &mut AuthRpcModule,
1075 node: &N,
1076 config: &NodeConfig<<N::Types as NodeTypes>::ChainSpec>,
1077 on_rpc_started: Box<dyn OnRpcStarted<N, EthB::EthApi>>,
1078 handles: RethRpcServerHandles,
1079 ) -> eyre::Result<()> {
1080 let ctx = RpcContext { node: node.clone(), config, registry, modules, auth_module };
1081
1082 on_rpc_started.on_rpc_started(ctx, handles)?;
1083 Ok(())
1084 }
1085}
1086
1087impl<N, EthB, PVB, EB, EVB, RpcMiddleware> NodeAddOns<N>
1088 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1089where
1090 N: FullNodeComponents,
1091 <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
1092 EthB: EthApiBuilder<N>,
1093 PVB: PayloadValidatorBuilder<N>,
1094 EB: EngineApiBuilder<N>,
1095 EVB: EngineValidatorBuilder<N>,
1096 RpcMiddleware: RethRpcMiddleware,
1097{
1098 type Handle = RpcHandle<N, EthB::EthApi>;
1099
1100 async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
1101 self.launch_add_ons_with(ctx, |_| Ok(())).await
1102 }
1103}
1104
1105pub trait RethRpcAddOns<N: FullNodeComponents>:
1108 NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
1109{
1110 type EthApi: EthApiTypes;
1112
1113 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
1115}
1116
1117impl<N: FullNodeComponents, EthB, EV, EB, Engine, RpcMiddleware> RethRpcAddOns<N>
1118 for RpcAddOns<N, EthB, EV, EB, Engine, RpcMiddleware>
1119where
1120 Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
1121 EthB: EthApiBuilder<N>,
1122{
1123 type EthApi = EthB::EthApi;
1124
1125 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
1126 &mut self.hooks
1127 }
1128}
1129
1130#[derive(Debug)]
1133pub struct EthApiCtx<'a, N: FullNodeTypes> {
1134 pub components: &'a N,
1136 pub config: EthConfig,
1138 pub cache: EthStateCache<PrimitivesTy<N::Types>>,
1140}
1141
1142impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>>>
1143 EthApiCtx<'a, N>
1144{
1145 pub fn eth_api_builder(self) -> reth_rpc::EthApiBuilder<N, EthRpcConverterFor<N>> {
1147 reth_rpc::EthApiBuilder::new_with_components(self.components.clone())
1148 .eth_cache(self.cache)
1149 .task_spawner(self.components.task_executor().clone())
1150 .gas_cap(self.config.rpc_gas_cap.into())
1151 .max_simulate_blocks(self.config.rpc_max_simulate_blocks)
1152 .eth_proof_window(self.config.eth_proof_window)
1153 .fee_history_cache_config(self.config.fee_history_cache)
1154 .proof_permits(self.config.proof_permits)
1155 .gas_oracle_config(self.config.gas_oracle)
1156 .max_batch_size(self.config.max_batch_size)
1157 .pending_block_kind(self.config.pending_block_kind)
1158 .raw_tx_forwarder(self.config.raw_tx_forwarder)
1159 .evm_memory_limit(self.config.rpc_evm_memory_limit)
1160 }
1161}
1162
1163pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
1165 type EthApi: EthApiTypes
1167 + FullEthApiServer<Provider = N::Provider, Pool = N::Pool>
1168 + Unpin
1169 + 'static;
1170
1171 fn build_eth_api(
1173 self,
1174 ctx: EthApiCtx<'_, N>,
1175 ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
1176}
1177
1178pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
1180 type ValidatorBuilder: EngineValidatorBuilder<Node>;
1182
1183 fn engine_validator_builder(&self) -> Self::ValidatorBuilder;
1185}
1186
1187impl<N, EthB, PVB, EB, EVB, RpcMiddleware> EngineValidatorAddOn<N>
1188 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1189where
1190 N: FullNodeComponents,
1191 EthB: EthApiBuilder<N>,
1192 PVB: Send,
1193 EB: EngineApiBuilder<N>,
1194 EVB: EngineValidatorBuilder<N>,
1195 RpcMiddleware: Send,
1196{
1197 type ValidatorBuilder = EVB;
1198
1199 fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
1200 self.engine_validator_builder.clone()
1201 }
1202}
1203
1204pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
1211 type EngineApi: IntoEngineApiRpcModule + Send + Sync;
1213
1214 fn build_engine_api(
1219 self,
1220 ctx: &AddOnsContext<'_, Node>,
1221 ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
1222}
1223
1224pub trait PayloadValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1229 type Validator: PayloadValidator<<Node::Types as NodeTypes>::Payload>;
1231
1232 fn build(
1237 self,
1238 ctx: &AddOnsContext<'_, Node>,
1239 ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
1240}
1241
1242pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1247 type EngineValidator: EngineValidator<
1249 <Node::Types as NodeTypes>::Payload,
1250 <Node::Types as NodeTypes>::Primitives,
1251 >;
1252
1253 fn build_tree_validator(
1257 self,
1258 ctx: &AddOnsContext<'_, Node>,
1259 tree_config: TreeConfig,
1260 ) -> impl Future<Output = eyre::Result<Self::EngineValidator>> + Send;
1261}
1262
1263#[derive(Debug, Clone)]
1267pub struct BasicEngineValidatorBuilder<EV> {
1268 payload_validator_builder: EV,
1270}
1271
1272impl<EV> BasicEngineValidatorBuilder<EV> {
1273 pub const fn new(payload_validator_builder: EV) -> Self {
1275 Self { payload_validator_builder }
1276 }
1277}
1278
1279impl<EV> Default for BasicEngineValidatorBuilder<EV>
1280where
1281 EV: Default,
1282{
1283 fn default() -> Self {
1284 Self::new(EV::default())
1285 }
1286}
1287
1288impl<Node, EV> EngineValidatorBuilder<Node> for BasicEngineValidatorBuilder<EV>
1289where
1290 Node: FullNodeComponents<
1291 Evm: ConfigureEngineEvm<
1292 <<Node::Types as NodeTypes>::Payload as PayloadTypes>::ExecutionData,
1293 >,
1294 >,
1295 EV: PayloadValidatorBuilder<Node>,
1296 EV::Validator: reth_engine_primitives::PayloadValidator<
1297 <Node::Types as NodeTypes>::Payload,
1298 Block = BlockTy<Node::Types>,
1299 >,
1300{
1301 type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
1302
1303 async fn build_tree_validator(
1304 self,
1305 ctx: &AddOnsContext<'_, Node>,
1306 tree_config: TreeConfig,
1307 ) -> eyre::Result<Self::EngineValidator> {
1308 let validator = self.payload_validator_builder.build(ctx).await?;
1309 let data_dir = ctx.config.datadir.clone().resolve_datadir(ctx.config.chain.chain());
1310 let invalid_block_hook = ctx.create_invalid_block_hook(&data_dir).await?;
1311 Ok(BasicEngineValidator::new(
1312 ctx.node.provider().clone(),
1313 std::sync::Arc::new(ctx.node.consensus().clone()),
1314 ctx.node.evm_config().clone(),
1315 validator,
1316 tree_config,
1317 invalid_block_hook,
1318 ))
1319 }
1320}
1321
1322#[derive(Debug, Default)]
1328pub struct BasicEngineApiBuilder<PVB> {
1329 payload_validator_builder: PVB,
1330}
1331
1332impl<N, PVB> EngineApiBuilder<N> for BasicEngineApiBuilder<PVB>
1333where
1334 N: FullNodeComponents<
1335 Types: NodeTypes<
1336 ChainSpec: EthereumHardforks,
1337 Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
1338 >,
1339 >,
1340 PVB: PayloadValidatorBuilder<N>,
1341 PVB::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
1342{
1343 type EngineApi = EngineApi<
1344 N::Provider,
1345 <N::Types as NodeTypes>::Payload,
1346 N::Pool,
1347 PVB::Validator,
1348 <N::Types as NodeTypes>::ChainSpec,
1349 >;
1350
1351 async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1352 let Self { payload_validator_builder } = self;
1353
1354 let engine_validator = payload_validator_builder.build(ctx).await?;
1355 let client = ClientVersionV1 {
1356 code: CLIENT_CODE,
1357 name: version_metadata().name_client.to_string(),
1358 version: version_metadata().cargo_pkg_version.to_string(),
1359 commit: version_metadata().vergen_git_sha.to_string(),
1360 };
1361 Ok(EngineApi::new(
1362 ctx.node.provider().clone(),
1363 ctx.config.chain.clone(),
1364 ctx.beacon_engine_handle.clone(),
1365 PayloadStore::new(ctx.node.payload_builder_handle().clone()),
1366 ctx.node.pool().clone(),
1367 Box::new(ctx.node.task_executor().clone()),
1368 client,
1369 EngineCapabilities::default(),
1370 engine_validator,
1371 ctx.config.engine.accept_execution_requests_hash,
1372 ))
1373 }
1374}
1375
1376#[derive(Debug, Clone, Default)]
1382#[non_exhaustive]
1383pub struct NoopEngineApiBuilder;
1384
1385impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
1386 type EngineApi = NoopEngineApi;
1387
1388 async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1389 Ok(NoopEngineApi::default())
1390 }
1391}
1392
1393#[derive(Debug, Clone, Default)]
1398#[non_exhaustive]
1399pub struct NoopEngineApi;
1400
1401impl IntoEngineApiRpcModule for NoopEngineApi {
1402 fn into_rpc_module(self) -> RpcModule<()> {
1403 RpcModule::new(())
1404 }
1405}