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