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