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 parking_lot::Mutex;
15use reth_chain_state::CanonStateSubscriptions;
16use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks, Hardforks};
17use reth_node_api::{
18 AddOnsContext, BlockTy, EngineApiValidator, EngineTypes, FullNodeComponents, FullNodeTypes,
19 NodeAddOns, NodeTypes, PayloadTypes, PayloadValidator, PrimitivesTy, TreeConfig,
20};
21use reth_node_core::{
22 cli::config::RethTransactionPoolConfig,
23 node_config::NodeConfig,
24 version::{version_metadata, CLIENT_CODE},
25};
26use reth_payload_builder::{PayloadBuilderHandle, PayloadStore};
27use reth_rpc::{
28 eth::{core::EthRpcConverterFor, DevSigner, EthApiTypes, FullEthApiServer},
29 AdminApi,
30};
31use reth_rpc_api::{eth::helpers::EthTransactions, IntoEngineApiRpcModule};
32use reth_rpc_builder::{
33 auth::{AuthRpcModule, AuthServerHandle},
34 config::RethRpcServerConfig,
35 RpcModuleBuilder, RpcRegistryInner, RpcServerConfig, RpcServerHandle, TransportRpcModules,
36};
37use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
38use reth_rpc_eth_types::{cache::cache_new_blocks_task, EthConfig, EthStateCache};
39use reth_tokio_util::EventSender;
40use reth_tracing::tracing::{debug, info};
41use std::{
42 fmt::{self, Debug},
43 future::Future,
44 ops::{Deref, DerefMut},
45 sync::Arc,
46};
47use tokio::sync::oneshot;
48
49#[derive(Debug, Clone)]
53pub struct RethRpcServerHandles {
54 pub rpc: RpcServerHandle,
56 pub auth: AuthServerHandle,
58}
59
60pub struct RpcHooks<Node: FullNodeComponents, EthApi> {
62 pub on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
64 pub extend_rpc_modules: Box<dyn ExtendRpcModules<Node, EthApi>>,
66}
67
68impl<Node, EthApi> Default for RpcHooks<Node, EthApi>
69where
70 Node: FullNodeComponents,
71 EthApi: EthApiTypes,
72{
73 fn default() -> Self {
74 Self { on_rpc_started: Box::<()>::default(), extend_rpc_modules: Box::<()>::default() }
75 }
76}
77
78impl<Node, EthApi> RpcHooks<Node, EthApi>
79where
80 Node: FullNodeComponents,
81 EthApi: EthApiTypes,
82{
83 pub(crate) fn set_on_rpc_started<F>(&mut self, hook: F) -> &mut Self
85 where
86 F: OnRpcStarted<Node, EthApi> + 'static,
87 {
88 self.on_rpc_started = Box::new(hook);
89 self
90 }
91
92 #[expect(unused)]
94 pub(crate) fn on_rpc_started<F>(mut self, hook: F) -> Self
95 where
96 F: OnRpcStarted<Node, EthApi> + 'static,
97 {
98 self.set_on_rpc_started(hook);
99 self
100 }
101
102 pub(crate) fn set_extend_rpc_modules<F>(&mut self, hook: F) -> &mut Self
104 where
105 F: ExtendRpcModules<Node, EthApi> + 'static,
106 {
107 self.extend_rpc_modules = Box::new(hook);
108 self
109 }
110
111 #[expect(unused)]
113 pub(crate) fn extend_rpc_modules<F>(mut self, hook: F) -> Self
114 where
115 F: ExtendRpcModules<Node, EthApi> + 'static,
116 {
117 self.set_extend_rpc_modules(hook);
118 self
119 }
120}
121
122impl<Node, EthApi> fmt::Debug for RpcHooks<Node, EthApi>
123where
124 Node: FullNodeComponents,
125 EthApi: EthApiTypes,
126{
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.debug_struct("RpcHooks")
129 .field("on_rpc_started", &"...")
130 .field("extend_rpc_modules", &"...")
131 .finish()
132 }
133}
134
135pub trait OnRpcStarted<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
137 fn on_rpc_started(
139 self: Box<Self>,
140 ctx: RpcContext<'_, Node, EthApi>,
141 handles: RethRpcServerHandles,
142 ) -> eyre::Result<()>;
143}
144
145impl<Node, EthApi, F> OnRpcStarted<Node, EthApi> for F
146where
147 F: FnOnce(RpcContext<'_, Node, EthApi>, RethRpcServerHandles) -> eyre::Result<()> + Send,
148 Node: FullNodeComponents,
149 EthApi: EthApiTypes,
150{
151 fn on_rpc_started(
152 self: Box<Self>,
153 ctx: RpcContext<'_, Node, EthApi>,
154 handles: RethRpcServerHandles,
155 ) -> eyre::Result<()> {
156 (*self)(ctx, handles)
157 }
158}
159
160impl<Node, EthApi> OnRpcStarted<Node, EthApi> for ()
161where
162 Node: FullNodeComponents,
163 EthApi: EthApiTypes,
164{
165 fn on_rpc_started(
166 self: Box<Self>,
167 _: RpcContext<'_, Node, EthApi>,
168 _: RethRpcServerHandles,
169 ) -> eyre::Result<()> {
170 Ok(())
171 }
172}
173
174pub trait ExtendRpcModules<Node: FullNodeComponents, EthApi: EthApiTypes>: Send {
176 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()>;
178}
179
180impl<Node, EthApi, F> ExtendRpcModules<Node, EthApi> for F
181where
182 F: FnOnce(RpcContext<'_, Node, EthApi>) -> eyre::Result<()> + Send,
183 Node: FullNodeComponents,
184 EthApi: EthApiTypes,
185{
186 fn extend_rpc_modules(self: Box<Self>, ctx: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
187 (*self)(ctx)
188 }
189}
190
191impl<Node, EthApi> ExtendRpcModules<Node, EthApi> for ()
192where
193 Node: FullNodeComponents,
194 EthApi: EthApiTypes,
195{
196 fn extend_rpc_modules(self: Box<Self>, _: RpcContext<'_, Node, EthApi>) -> eyre::Result<()> {
197 Ok(())
198 }
199}
200
201#[derive(Debug, Clone)]
203#[expect(clippy::type_complexity)]
204pub struct RpcRegistry<Node: FullNodeComponents, EthApi: EthApiTypes> {
205 pub(crate) registry: RpcRegistryInner<
206 Node::Provider,
207 Node::Pool,
208 Node::Network,
209 EthApi,
210 Node::Evm,
211 Node::Consensus,
212 >,
213}
214
215impl<Node, EthApi> Deref for RpcRegistry<Node, EthApi>
216where
217 Node: FullNodeComponents,
218 EthApi: EthApiTypes,
219{
220 type Target = RpcRegistryInner<
221 Node::Provider,
222 Node::Pool,
223 Node::Network,
224 EthApi,
225 Node::Evm,
226 Node::Consensus,
227 >;
228
229 fn deref(&self) -> &Self::Target {
230 &self.registry
231 }
232}
233
234impl<Node, EthApi> DerefMut for RpcRegistry<Node, EthApi>
235where
236 Node: FullNodeComponents,
237 EthApi: EthApiTypes,
238{
239 fn deref_mut(&mut self) -> &mut Self::Target {
240 &mut self.registry
241 }
242}
243
244#[expect(missing_debug_implementations)]
246pub struct RpcModuleContainer<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
247 pub modules: &'a mut TransportRpcModules,
249 pub auth_module: &'a mut AuthRpcModule,
251 pub registry: &'a mut RpcRegistry<Node, EthApi>,
253}
254
255#[expect(missing_debug_implementations)]
263pub struct RpcContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
264 pub(crate) node: Node,
266
267 pub(crate) config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
269
270 pub registry: &'a mut RpcRegistry<Node, EthApi>,
274 pub modules: &'a mut TransportRpcModules,
279 pub auth_module: &'a mut AuthRpcModule,
283}
284
285impl<Node, EthApi> RpcContext<'_, Node, EthApi>
286where
287 Node: FullNodeComponents,
288 EthApi: EthApiTypes,
289{
290 pub const fn config(&self) -> &NodeConfig<<Node::Types as NodeTypes>::ChainSpec> {
292 self.config
293 }
294
295 pub const fn node(&self) -> &Node {
299 &self.node
300 }
301
302 pub fn pool(&self) -> &Node::Pool {
304 self.node.pool()
305 }
306
307 pub fn provider(&self) -> &Node::Provider {
309 self.node.provider()
310 }
311
312 pub fn network(&self) -> &Node::Network {
314 self.node.network()
315 }
316
317 pub fn payload_builder_handle(
319 &self,
320 ) -> &PayloadBuilderHandle<<Node::Types as NodeTypes>::Payload> {
321 self.node.payload_builder_handle()
322 }
323}
324
325pub struct RpcHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
327 pub rpc_server_handles: RethRpcServerHandles,
329 pub rpc_registry: RpcRegistry<Node, EthApi>,
331 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
336 pub beacon_engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
338 pub engine_shutdown: EngineShutdown,
340}
341
342impl<Node: FullNodeComponents, EthApi: EthApiTypes> Clone for RpcHandle<Node, EthApi> {
343 fn clone(&self) -> Self {
344 Self {
345 rpc_server_handles: self.rpc_server_handles.clone(),
346 rpc_registry: self.rpc_registry.clone(),
347 engine_events: self.engine_events.clone(),
348 beacon_engine_handle: self.beacon_engine_handle.clone(),
349 engine_shutdown: self.engine_shutdown.clone(),
350 }
351 }
352}
353
354impl<Node: FullNodeComponents, EthApi: EthApiTypes> Deref for RpcHandle<Node, EthApi> {
355 type Target = RpcRegistry<Node, EthApi>;
356
357 fn deref(&self) -> &Self::Target {
358 &self.rpc_registry
359 }
360}
361
362impl<Node: FullNodeComponents, EthApi: EthApiTypes> Debug for RpcHandle<Node, EthApi>
363where
364 RpcRegistry<Node, EthApi>: Debug,
365{
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 f.debug_struct("RpcHandle")
368 .field("rpc_server_handles", &self.rpc_server_handles)
369 .field("rpc_registry", &self.rpc_registry)
370 .field("engine_shutdown", &self.engine_shutdown)
371 .finish()
372 }
373}
374
375impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcHandle<Node, EthApi> {
376 pub const fn rpc_server_handles(&self) -> &RethRpcServerHandles {
378 &self.rpc_server_handles
379 }
380
381 pub const fn consensus_engine_handle(
385 &self,
386 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
387 &self.beacon_engine_handle
388 }
389
390 pub const fn consensus_engine_events(
392 &self,
393 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
394 &self.engine_events
395 }
396
397 pub const fn eth_api(&self) -> &EthApi {
399 self.rpc_registry.registry.eth_api()
400 }
401
402 pub fn admin_api(
404 &self,
405 ) -> AdminApi<Node::Network, <Node::Types as NodeTypes>::ChainSpec, Node::Pool>
406 where
407 <Node::Types as NodeTypes>::ChainSpec: EthereumHardforks,
408 {
409 self.rpc_registry.registry.admin_api()
410 }
411}
412
413#[derive(Debug, Clone)]
419pub struct RpcServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
420 pub rpc_server_handle: RpcServerHandle,
422 pub rpc_registry: RpcRegistry<Node, EthApi>,
424 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
426 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
428}
429
430impl<Node: FullNodeComponents, EthApi: EthApiTypes> RpcServerOnlyHandle<Node, EthApi> {
431 pub const fn rpc_server_handle(&self) -> &RpcServerHandle {
433 &self.rpc_server_handle
434 }
435
436 pub const fn consensus_engine_handle(
440 &self,
441 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
442 &self.engine_handle
443 }
444
445 pub const fn consensus_engine_events(
447 &self,
448 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
449 &self.engine_events
450 }
451}
452
453#[derive(Debug, Clone)]
459pub struct AuthServerOnlyHandle<Node: FullNodeComponents, EthApi: EthApiTypes> {
460 pub auth_server_handle: AuthServerHandle,
462 pub rpc_registry: RpcRegistry<Node, EthApi>,
464 pub engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
466 pub engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
468}
469
470impl<Node: FullNodeComponents, EthApi: EthApiTypes> AuthServerOnlyHandle<Node, EthApi> {
471 pub const fn consensus_engine_handle(
475 &self,
476 ) -> &ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload> {
477 &self.engine_handle
478 }
479
480 pub const fn consensus_engine_events(
482 &self,
483 ) -> &EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>> {
484 &self.engine_events
485 }
486}
487
488struct RpcSetupContext<'a, Node: FullNodeComponents, EthApi: EthApiTypes> {
490 node: Node,
491 config: &'a NodeConfig<<Node::Types as NodeTypes>::ChainSpec>,
492 modules: TransportRpcModules,
493 auth_module: AuthRpcModule,
494 auth_config: reth_rpc_builder::auth::AuthServerConfig,
495 registry: RpcRegistry<Node, EthApi>,
496 on_rpc_started: Box<dyn OnRpcStarted<Node, EthApi>>,
497 engine_events: EventSender<ConsensusEngineEvent<<Node::Types as NodeTypes>::Primitives>>,
498 engine_handle: ConsensusEngineHandle<<Node::Types as NodeTypes>::Payload>,
499}
500
501pub struct RpcAddOns<
512 Node: FullNodeComponents,
513 EthB: EthApiBuilder<Node>,
514 PVB,
515 EB = BasicEngineApiBuilder<PVB>,
516 EVB = BasicEngineValidatorBuilder<PVB>,
517 RpcMiddleware = Identity,
518> {
519 pub hooks: RpcHooks<Node, EthB::EthApi>,
521 eth_api_builder: EthB,
523 payload_validator_builder: PVB,
525 engine_api_builder: EB,
527 engine_validator_builder: EVB,
529 rpc_middleware: RpcMiddleware,
534 tokio_runtime: Option<tokio::runtime::Handle>,
536}
537
538impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> Debug
539 for RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
540where
541 Node: FullNodeComponents,
542 EthB: EthApiBuilder<Node>,
543 PVB: Debug,
544 EB: Debug,
545 EVB: Debug,
546{
547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 f.debug_struct("RpcAddOns")
549 .field("hooks", &self.hooks)
550 .field("eth_api_builder", &"...")
551 .field("payload_validator_builder", &self.payload_validator_builder)
552 .field("engine_api_builder", &self.engine_api_builder)
553 .field("engine_validator_builder", &self.engine_validator_builder)
554 .field("rpc_middleware", &"...")
555 .finish()
556 }
557}
558
559impl<Node, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<Node, EthB, PVB, EB, EVB, RpcMiddleware>
560where
561 Node: FullNodeComponents,
562 EthB: EthApiBuilder<Node>,
563{
564 pub fn new(
566 eth_api_builder: EthB,
567 payload_validator_builder: PVB,
568 engine_api_builder: EB,
569 engine_validator_builder: EVB,
570 rpc_middleware: RpcMiddleware,
571 ) -> Self {
572 Self {
573 hooks: RpcHooks::default(),
574 eth_api_builder,
575 payload_validator_builder,
576 engine_api_builder,
577 engine_validator_builder,
578 rpc_middleware,
579 tokio_runtime: None,
580 }
581 }
582
583 pub fn with_engine_api<T>(
585 self,
586 engine_api_builder: T,
587 ) -> RpcAddOns<Node, EthB, PVB, T, EVB, RpcMiddleware> {
588 let Self {
589 hooks,
590 eth_api_builder,
591 payload_validator_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_payload_validator<T>(
610 self,
611 payload_validator_builder: T,
612 ) -> RpcAddOns<Node, EthB, T, EB, EVB, RpcMiddleware> {
613 let Self {
614 hooks,
615 eth_api_builder,
616 engine_api_builder,
617 engine_validator_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_engine_validator<T>(
635 self,
636 engine_validator_builder: T,
637 ) -> RpcAddOns<Node, EthB, PVB, EB, T, RpcMiddleware> {
638 let Self {
639 hooks,
640 eth_api_builder,
641 payload_validator_builder,
642 engine_api_builder,
643 rpc_middleware,
644 tokio_runtime,
645 ..
646 } = self;
647 RpcAddOns {
648 hooks,
649 eth_api_builder,
650 payload_validator_builder,
651 engine_api_builder,
652 engine_validator_builder,
653 rpc_middleware,
654 tokio_runtime,
655 }
656 }
657
658 pub fn with_rpc_middleware<T>(
697 self,
698 rpc_middleware: T,
699 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, T> {
700 let Self {
701 hooks,
702 eth_api_builder,
703 payload_validator_builder,
704 engine_api_builder,
705 engine_validator_builder,
706 tokio_runtime,
707 ..
708 } = self;
709 RpcAddOns {
710 hooks,
711 eth_api_builder,
712 payload_validator_builder,
713 engine_api_builder,
714 engine_validator_builder,
715 rpc_middleware,
716 tokio_runtime,
717 }
718 }
719
720 pub fn with_tokio_runtime(self, tokio_runtime: Option<tokio::runtime::Handle>) -> Self {
724 let Self {
725 hooks,
726 eth_api_builder,
727 payload_validator_builder,
728 engine_validator_builder,
729 engine_api_builder,
730 rpc_middleware,
731 ..
732 } = self;
733 Self {
734 hooks,
735 eth_api_builder,
736 payload_validator_builder,
737 engine_validator_builder,
738 engine_api_builder,
739 rpc_middleware,
740 tokio_runtime,
741 }
742 }
743
744 pub fn layer_rpc_middleware<T>(
746 self,
747 layer: T,
748 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, T>> {
749 let Self {
750 hooks,
751 eth_api_builder,
752 payload_validator_builder,
753 engine_api_builder,
754 engine_validator_builder,
755 rpc_middleware,
756 tokio_runtime,
757 } = self;
758 let rpc_middleware = Stack::new(rpc_middleware, layer);
759 RpcAddOns {
760 hooks,
761 eth_api_builder,
762 payload_validator_builder,
763 engine_api_builder,
764 engine_validator_builder,
765 rpc_middleware,
766 tokio_runtime,
767 }
768 }
769
770 #[expect(clippy::type_complexity)]
772 pub fn option_layer_rpc_middleware<T>(
773 self,
774 layer: Option<T>,
775 ) -> RpcAddOns<Node, EthB, PVB, EB, EVB, Stack<RpcMiddleware, Either<T, Identity>>> {
776 let layer = layer.map(Either::Left).unwrap_or(Either::Right(Identity::new()));
777 self.layer_rpc_middleware(layer)
778 }
779
780 pub fn on_rpc_started<F>(mut self, hook: F) -> Self
782 where
783 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>, RethRpcServerHandles) -> eyre::Result<()>
784 + Send
785 + 'static,
786 {
787 self.hooks.set_on_rpc_started(hook);
788 self
789 }
790
791 pub fn extend_rpc_modules<F>(mut self, hook: F) -> Self
793 where
794 F: FnOnce(RpcContext<'_, Node, EthB::EthApi>) -> eyre::Result<()> + Send + 'static,
795 {
796 self.hooks.set_extend_rpc_modules(hook);
797 self
798 }
799}
800
801impl<Node, EthB, EV, EB, Engine> Default for RpcAddOns<Node, EthB, EV, EB, Engine, Identity>
802where
803 Node: FullNodeComponents,
804 EthB: EthApiBuilder<Node>,
805 EV: Default,
806 EB: Default,
807 Engine: Default,
808{
809 fn default() -> Self {
810 Self::new(
811 EthB::default(),
812 EV::default(),
813 EB::default(),
814 Engine::default(),
815 Default::default(),
816 )
817 }
818}
819
820impl<N, EthB, PVB, EB, EVB, RpcMiddleware> RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
821where
822 N: FullNodeComponents,
823 N::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
824 EthB: EthApiBuilder<N>,
825 EB: EngineApiBuilder<N>,
826 EVB: EngineValidatorBuilder<N>,
827 RpcMiddleware: RethRpcMiddleware,
828{
829 pub async fn launch_rpc_server<F>(
835 self,
836 ctx: AddOnsContext<'_, N>,
837 ext: F,
838 ) -> eyre::Result<RpcServerOnlyHandle<N, EthB::EthApi>>
839 where
840 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
841 {
842 let rpc_middleware = self.rpc_middleware.clone();
843 let tokio_runtime = self.tokio_runtime.clone();
844 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
845 let RpcSetupContext {
846 node,
847 config,
848 mut modules,
849 mut auth_module,
850 auth_config: _,
851 mut registry,
852 on_rpc_started,
853 engine_events,
854 engine_handle,
855 } = setup_ctx;
856
857 let server_config = config
858 .rpc
859 .rpc_server_config()
860 .set_rpc_middleware(rpc_middleware)
861 .with_tokio_runtime(tokio_runtime);
862 let rpc_server_handle = Self::launch_rpc_server_internal(server_config, &modules).await?;
863
864 let handles =
865 RethRpcServerHandles { rpc: rpc_server_handle.clone(), auth: AuthServerHandle::noop() };
866 Self::finalize_rpc_setup(
867 &mut registry,
868 &mut modules,
869 &mut auth_module,
870 &node,
871 config,
872 on_rpc_started,
873 handles,
874 )?;
875
876 Ok(RpcServerOnlyHandle {
877 rpc_server_handle,
878 rpc_registry: registry,
879 engine_events,
880 engine_handle,
881 })
882 }
883
884 pub async fn launch_add_ons_with<F>(
887 self,
888 ctx: AddOnsContext<'_, N>,
889 ext: F,
890 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
891 where
892 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
893 {
894 let disable_auth = ctx.config.rpc.disable_auth_server;
896 self.launch_add_ons_with_opt_engine(ctx, ext, disable_auth).await
897 }
898
899 pub async fn launch_add_ons_with_opt_engine<F>(
905 self,
906 ctx: AddOnsContext<'_, N>,
907 ext: F,
908 disable_auth: bool,
909 ) -> eyre::Result<RpcHandle<N, EthB::EthApi>>
910 where
911 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
912 {
913 let rpc_middleware = self.rpc_middleware.clone();
914 let tokio_runtime = self.tokio_runtime.clone();
915 let setup_ctx = self.setup_rpc_components(ctx, ext).await?;
916 let RpcSetupContext {
917 node,
918 config,
919 mut modules,
920 mut auth_module,
921 auth_config,
922 mut registry,
923 on_rpc_started,
924 engine_events,
925 engine_handle,
926 } = setup_ctx;
927
928 let server_config = config
929 .rpc
930 .rpc_server_config()
931 .set_rpc_middleware(rpc_middleware)
932 .with_tokio_runtime(tokio_runtime);
933
934 let (rpc, auth) = if disable_auth {
935 let rpc = Self::launch_rpc_server_internal(server_config, &modules).await?;
937 (rpc, AuthServerHandle::noop())
938 } else {
939 let auth_module_clone = auth_module.clone();
940 let (rpc, auth) = futures::future::try_join(
942 Self::launch_rpc_server_internal(server_config, &modules),
943 Self::launch_auth_server_internal(auth_module_clone, auth_config),
944 )
945 .await?;
946 (rpc, auth)
947 };
948
949 let handles = RethRpcServerHandles { rpc, auth };
950
951 Self::finalize_rpc_setup(
952 &mut registry,
953 &mut modules,
954 &mut auth_module,
955 &node,
956 config,
957 on_rpc_started,
958 handles.clone(),
959 )?;
960
961 Ok(RpcHandle {
962 rpc_server_handles: handles,
963 rpc_registry: registry,
964 engine_events,
965 beacon_engine_handle: engine_handle,
966 engine_shutdown: EngineShutdown::default(),
967 })
968 }
969
970 async fn setup_rpc_components<'a, F>(
972 self,
973 ctx: AddOnsContext<'a, N>,
974 ext: F,
975 ) -> eyre::Result<RpcSetupContext<'a, N, EthB::EthApi>>
976 where
977 F: FnOnce(RpcModuleContainer<'_, N, EthB::EthApi>) -> eyre::Result<()>,
978 {
979 let Self { eth_api_builder, engine_api_builder, hooks, .. } = self;
980
981 let engine_api = engine_api_builder.build_engine_api(&ctx).await?;
982 let AddOnsContext { node, config, beacon_engine_handle, jwt_secret, engine_events } = ctx;
983
984 info!(target: "reth::cli", "Engine API handler initialized");
985
986 let cache = EthStateCache::spawn_with(
987 node.provider().clone(),
988 config.rpc.eth_config().cache,
989 node.task_executor().clone(),
990 );
991
992 let new_canonical_blocks = node.provider().canonical_state_stream();
993 let c = cache.clone();
994 node.task_executor().spawn_critical(
995 "cache canonical blocks task",
996 Box::pin(async move {
997 cache_new_blocks_task(c, new_canonical_blocks).await;
998 }),
999 );
1000
1001 let eth_config = config.rpc.eth_config().max_batch_size(config.txpool.max_batch_size());
1002 let ctx = EthApiCtx {
1003 components: &node,
1004 config: eth_config,
1005 cache,
1006 engine_handle: beacon_engine_handle.clone(),
1007 };
1008 let eth_api = eth_api_builder.build_eth_api(ctx).await?;
1009
1010 let auth_config = config.rpc.auth_server_config(jwt_secret)?;
1011 let module_config = config.rpc.transport_rpc_module_config();
1012 debug!(target: "reth::cli", http=?module_config.http(), ws=?module_config.ws(), "Using RPC module config");
1013
1014 let (mut modules, mut auth_module, registry) = RpcModuleBuilder::default()
1015 .with_provider(node.provider().clone())
1016 .with_pool(node.pool().clone())
1017 .with_network(node.network().clone())
1018 .with_executor(Box::new(node.task_executor().clone()))
1019 .with_evm_config(node.evm_config().clone())
1020 .with_consensus(node.consensus().clone())
1021 .build_with_auth_server(module_config, engine_api, eth_api, engine_events.clone());
1022
1023 if config.dev.dev {
1025 let signers = DevSigner::from_mnemonic(config.dev.dev_mnemonic.as_str(), 20);
1026 registry.eth_api().signers().write().extend(signers);
1027 }
1028
1029 let mut registry = RpcRegistry { registry };
1030 let ctx = RpcContext {
1031 node: node.clone(),
1032 config,
1033 registry: &mut registry,
1034 modules: &mut modules,
1035 auth_module: &mut auth_module,
1036 };
1037
1038 let RpcHooks { on_rpc_started, extend_rpc_modules } = hooks;
1039
1040 ext(RpcModuleContainer {
1041 modules: ctx.modules,
1042 auth_module: ctx.auth_module,
1043 registry: ctx.registry,
1044 })?;
1045 extend_rpc_modules.extend_rpc_modules(ctx)?;
1046
1047 Ok(RpcSetupContext {
1048 node,
1049 config,
1050 modules,
1051 auth_module,
1052 auth_config,
1053 registry,
1054 on_rpc_started,
1055 engine_events,
1056 engine_handle: beacon_engine_handle,
1057 })
1058 }
1059
1060 async fn launch_rpc_server_internal<M>(
1062 server_config: RpcServerConfig<M>,
1063 modules: &TransportRpcModules,
1064 ) -> eyre::Result<RpcServerHandle>
1065 where
1066 M: RethRpcMiddleware,
1067 {
1068 let handle = server_config.start(modules).await?;
1069
1070 if let Some(path) = handle.ipc_endpoint() {
1071 info!(target: "reth::cli", %path, "RPC IPC server started");
1072 }
1073 if let Some(addr) = handle.http_local_addr() {
1074 info!(target: "reth::cli", url=%addr, "RPC HTTP server started");
1075 }
1076 if let Some(addr) = handle.ws_local_addr() {
1077 info!(target: "reth::cli", url=%addr, "RPC WS server started");
1078 }
1079
1080 Ok(handle)
1081 }
1082
1083 async fn launch_auth_server_internal(
1085 auth_module: AuthRpcModule,
1086 auth_config: reth_rpc_builder::auth::AuthServerConfig,
1087 ) -> eyre::Result<AuthServerHandle> {
1088 auth_module.start_server(auth_config)
1089 .await
1090 .map_err(Into::into)
1091 .inspect(|handle| {
1092 let addr = handle.local_addr();
1093 if let Some(ipc_endpoint) = handle.ipc_endpoint() {
1094 info!(target: "reth::cli", url=%addr, ipc_endpoint=%ipc_endpoint, "RPC auth server started");
1095 } else {
1096 info!(target: "reth::cli", url=%addr, "RPC auth server started");
1097 }
1098 })
1099 }
1100
1101 fn finalize_rpc_setup(
1103 registry: &mut RpcRegistry<N, EthB::EthApi>,
1104 modules: &mut TransportRpcModules,
1105 auth_module: &mut AuthRpcModule,
1106 node: &N,
1107 config: &NodeConfig<<N::Types as NodeTypes>::ChainSpec>,
1108 on_rpc_started: Box<dyn OnRpcStarted<N, EthB::EthApi>>,
1109 handles: RethRpcServerHandles,
1110 ) -> eyre::Result<()> {
1111 let ctx = RpcContext { node: node.clone(), config, registry, modules, auth_module };
1112
1113 on_rpc_started.on_rpc_started(ctx, handles)?;
1114 Ok(())
1115 }
1116}
1117
1118impl<N, EthB, PVB, EB, EVB, RpcMiddleware> NodeAddOns<N>
1119 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1120where
1121 N: FullNodeComponents,
1122 <N as FullNodeTypes>::Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>,
1123 EthB: EthApiBuilder<N>,
1124 PVB: PayloadValidatorBuilder<N>,
1125 EB: EngineApiBuilder<N>,
1126 EVB: EngineValidatorBuilder<N>,
1127 RpcMiddleware: RethRpcMiddleware,
1128{
1129 type Handle = RpcHandle<N, EthB::EthApi>;
1130
1131 async fn launch_add_ons(self, ctx: AddOnsContext<'_, N>) -> eyre::Result<Self::Handle> {
1132 self.launch_add_ons_with(ctx, |_| Ok(())).await
1133 }
1134}
1135
1136pub trait RethRpcAddOns<N: FullNodeComponents>:
1139 NodeAddOns<N, Handle = RpcHandle<N, Self::EthApi>>
1140{
1141 type EthApi: EthApiTypes;
1143
1144 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi>;
1146}
1147
1148impl<N: FullNodeComponents, EthB, EV, EB, Engine, RpcMiddleware> RethRpcAddOns<N>
1149 for RpcAddOns<N, EthB, EV, EB, Engine, RpcMiddleware>
1150where
1151 Self: NodeAddOns<N, Handle = RpcHandle<N, EthB::EthApi>>,
1152 EthB: EthApiBuilder<N>,
1153{
1154 type EthApi = EthB::EthApi;
1155
1156 fn hooks_mut(&mut self) -> &mut RpcHooks<N, Self::EthApi> {
1157 &mut self.hooks
1158 }
1159}
1160
1161#[derive(Debug)]
1164pub struct EthApiCtx<'a, N: FullNodeTypes> {
1165 pub components: &'a N,
1167 pub config: EthConfig,
1169 pub cache: EthStateCache<PrimitivesTy<N::Types>>,
1171 pub engine_handle: ConsensusEngineHandle<<N::Types as NodeTypes>::Payload>,
1173}
1174
1175impl<'a, N: FullNodeComponents<Types: NodeTypes<ChainSpec: Hardforks + EthereumHardforks>>>
1176 EthApiCtx<'a, N>
1177{
1178 pub fn eth_api_builder(self) -> reth_rpc::EthApiBuilder<N, EthRpcConverterFor<N>> {
1180 reth_rpc::EthApiBuilder::new_with_components(self.components.clone())
1181 .eth_cache(self.cache)
1182 .task_spawner(self.components.task_executor().clone())
1183 .gas_cap(self.config.rpc_gas_cap.into())
1184 .max_simulate_blocks(self.config.rpc_max_simulate_blocks)
1185 .eth_proof_window(self.config.eth_proof_window)
1186 .fee_history_cache_config(self.config.fee_history_cache)
1187 .proof_permits(self.config.proof_permits)
1188 .gas_oracle_config(self.config.gas_oracle)
1189 .max_batch_size(self.config.max_batch_size)
1190 .max_blocking_io_requests(self.config.max_blocking_io_requests)
1191 .pending_block_kind(self.config.pending_block_kind)
1192 .raw_tx_forwarder(self.config.raw_tx_forwarder)
1193 .evm_memory_limit(self.config.rpc_evm_memory_limit)
1194 }
1195}
1196
1197pub trait EthApiBuilder<N: FullNodeComponents>: Default + Send + 'static {
1199 type EthApi: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>;
1201
1202 fn build_eth_api(
1204 self,
1205 ctx: EthApiCtx<'_, N>,
1206 ) -> impl Future<Output = eyre::Result<Self::EthApi>> + Send;
1207}
1208
1209pub trait EngineValidatorAddOn<Node: FullNodeComponents>: Send {
1211 type ValidatorBuilder: EngineValidatorBuilder<Node>;
1213
1214 fn engine_validator_builder(&self) -> Self::ValidatorBuilder;
1216}
1217
1218impl<N, EthB, PVB, EB, EVB, RpcMiddleware> EngineValidatorAddOn<N>
1219 for RpcAddOns<N, EthB, PVB, EB, EVB, RpcMiddleware>
1220where
1221 N: FullNodeComponents,
1222 EthB: EthApiBuilder<N>,
1223 PVB: Send,
1224 EB: EngineApiBuilder<N>,
1225 EVB: EngineValidatorBuilder<N>,
1226 RpcMiddleware: Send,
1227{
1228 type ValidatorBuilder = EVB;
1229
1230 fn engine_validator_builder(&self) -> Self::ValidatorBuilder {
1231 self.engine_validator_builder.clone()
1232 }
1233}
1234
1235pub trait EngineApiBuilder<Node: FullNodeComponents>: Send + Sync {
1242 type EngineApi: IntoEngineApiRpcModule + Send + Sync;
1244
1245 fn build_engine_api(
1250 self,
1251 ctx: &AddOnsContext<'_, Node>,
1252 ) -> impl Future<Output = eyre::Result<Self::EngineApi>> + Send;
1253}
1254
1255pub trait PayloadValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1260 type Validator: PayloadValidator<<Node::Types as NodeTypes>::Payload>;
1262
1263 fn build(
1268 self,
1269 ctx: &AddOnsContext<'_, Node>,
1270 ) -> impl Future<Output = eyre::Result<Self::Validator>> + Send;
1271}
1272
1273pub trait EngineValidatorBuilder<Node: FullNodeComponents>: Send + Sync + Clone {
1278 type EngineValidator: EngineValidator<
1280 <Node::Types as NodeTypes>::Payload,
1281 <Node::Types as NodeTypes>::Primitives,
1282 >;
1283
1284 fn build_tree_validator(
1288 self,
1289 ctx: &AddOnsContext<'_, Node>,
1290 tree_config: TreeConfig,
1291 ) -> impl Future<Output = eyre::Result<Self::EngineValidator>> + Send;
1292}
1293
1294#[derive(Debug, Clone)]
1298pub struct BasicEngineValidatorBuilder<EV> {
1299 payload_validator_builder: EV,
1301}
1302
1303impl<EV> BasicEngineValidatorBuilder<EV> {
1304 pub const fn new(payload_validator_builder: EV) -> Self {
1306 Self { payload_validator_builder }
1307 }
1308}
1309
1310impl<EV> Default for BasicEngineValidatorBuilder<EV>
1311where
1312 EV: Default,
1313{
1314 fn default() -> Self {
1315 Self::new(EV::default())
1316 }
1317}
1318
1319impl<Node, EV> EngineValidatorBuilder<Node> for BasicEngineValidatorBuilder<EV>
1320where
1321 Node: FullNodeComponents<
1322 Evm: ConfigureEngineEvm<
1323 <<Node::Types as NodeTypes>::Payload as PayloadTypes>::ExecutionData,
1324 >,
1325 >,
1326 EV: PayloadValidatorBuilder<Node>,
1327 EV::Validator: reth_engine_primitives::PayloadValidator<
1328 <Node::Types as NodeTypes>::Payload,
1329 Block = BlockTy<Node::Types>,
1330 >,
1331{
1332 type EngineValidator = BasicEngineValidator<Node::Provider, Node::Evm, EV::Validator>;
1333
1334 async fn build_tree_validator(
1335 self,
1336 ctx: &AddOnsContext<'_, Node>,
1337 tree_config: TreeConfig,
1338 ) -> eyre::Result<Self::EngineValidator> {
1339 let validator = self.payload_validator_builder.build(ctx).await?;
1340 let data_dir = ctx.config.datadir.clone().resolve_datadir(ctx.config.chain.chain());
1341 let invalid_block_hook = ctx.create_invalid_block_hook(&data_dir).await?;
1342 Ok(BasicEngineValidator::new(
1343 ctx.node.provider().clone(),
1344 std::sync::Arc::new(ctx.node.consensus().clone()),
1345 ctx.node.evm_config().clone(),
1346 validator,
1347 tree_config,
1348 invalid_block_hook,
1349 ))
1350 }
1351}
1352
1353#[derive(Debug, Default)]
1359pub struct BasicEngineApiBuilder<PVB> {
1360 payload_validator_builder: PVB,
1361}
1362
1363impl<N, PVB> EngineApiBuilder<N> for BasicEngineApiBuilder<PVB>
1364where
1365 N: FullNodeComponents<
1366 Types: NodeTypes<
1367 ChainSpec: EthereumHardforks,
1368 Payload: PayloadTypes<ExecutionData = ExecutionData> + EngineTypes,
1369 >,
1370 >,
1371 PVB: PayloadValidatorBuilder<N>,
1372 PVB::Validator: EngineApiValidator<<N::Types as NodeTypes>::Payload>,
1373{
1374 type EngineApi = EngineApi<
1375 N::Provider,
1376 <N::Types as NodeTypes>::Payload,
1377 N::Pool,
1378 PVB::Validator,
1379 <N::Types as NodeTypes>::ChainSpec,
1380 >;
1381
1382 async fn build_engine_api(self, ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1383 let Self { payload_validator_builder } = self;
1384
1385 let engine_validator = payload_validator_builder.build(ctx).await?;
1386 let client = ClientVersionV1 {
1387 code: CLIENT_CODE,
1388 name: version_metadata().name_client.to_string(),
1389 version: version_metadata().cargo_pkg_version.to_string(),
1390 commit: version_metadata().vergen_git_sha.to_string(),
1391 };
1392
1393 Ok(EngineApi::new(
1394 ctx.node.provider().clone(),
1395 ctx.config.chain.clone(),
1396 ctx.beacon_engine_handle.clone(),
1397 PayloadStore::new(ctx.node.payload_builder_handle().clone()),
1398 ctx.node.pool().clone(),
1399 Box::new(ctx.node.task_executor().clone()),
1400 client,
1401 EngineCapabilities::default(),
1402 engine_validator,
1403 ctx.config.engine.accept_execution_requests_hash,
1404 ctx.node.network().clone(),
1405 ))
1406 }
1407}
1408
1409#[derive(Debug, Clone, Default)]
1415#[non_exhaustive]
1416pub struct NoopEngineApiBuilder;
1417
1418impl<N: FullNodeComponents> EngineApiBuilder<N> for NoopEngineApiBuilder {
1419 type EngineApi = NoopEngineApi;
1420
1421 async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
1422 Ok(NoopEngineApi::default())
1423 }
1424}
1425
1426#[derive(Debug, Clone, Default)]
1431#[non_exhaustive]
1432pub struct NoopEngineApi;
1433
1434impl IntoEngineApiRpcModule for NoopEngineApi {
1435 fn into_rpc_module(self) -> RpcModule<()> {
1436 RpcModule::new(())
1437 }
1438}
1439
1440#[derive(Clone, Debug)]
1445pub struct EngineShutdown {
1446 tx: Arc<Mutex<Option<oneshot::Sender<EngineShutdownRequest>>>>,
1448}
1449
1450impl EngineShutdown {
1451 pub fn new() -> (Self, oneshot::Receiver<EngineShutdownRequest>) {
1453 let (tx, rx) = oneshot::channel();
1454 (Self { tx: Arc::new(Mutex::new(Some(tx))) }, rx)
1455 }
1456
1457 pub fn shutdown(&self) -> Option<oneshot::Receiver<()>> {
1464 let mut guard = self.tx.lock();
1465 let tx = guard.take()?;
1466 let (done_tx, done_rx) = oneshot::channel();
1467 let _ = tx.send(EngineShutdownRequest { done_tx });
1468 Some(done_rx)
1469 }
1470}
1471
1472impl Default for EngineShutdown {
1473 fn default() -> Self {
1474 Self { tx: Arc::new(Mutex::new(None)) }
1475 }
1476}
1477
1478#[derive(Debug)]
1480pub struct EngineShutdownRequest {
1481 pub done_tx: oneshot::Sender<()>,
1483}