1
1
//! Builder support for rpc components.
2
2
3
+ pub use jsonrpsee:: server:: middleware:: rpc:: { RpcService , RpcServiceBuilder } ;
4
+ pub use reth_rpc_builder:: { Identity , RpcRequestMetricsService } ;
5
+
3
6
use crate :: { BeaconConsensusEngineEvent , BeaconConsensusEngineHandle } ;
4
7
use alloy_rpc_types:: engine:: ClientVersionV1 ;
5
8
use alloy_rpc_types_engine:: ExecutionData ;
@@ -31,6 +34,7 @@ use std::{
31
34
future:: Future ,
32
35
ops:: { Deref , DerefMut } ,
33
36
} ;
37
+ use tower:: Layer ;
34
38
35
39
/// Contains the handles to the spawned RPC servers.
36
40
///
@@ -417,6 +421,7 @@ pub struct RpcAddOns<
417
421
EthB : EthApiBuilder < Node > ,
418
422
EV ,
419
423
EB = BasicEngineApiBuilder < EV > ,
424
+ RpcMiddleware = Identity ,
420
425
> {
421
426
/// Additional RPC add-ons.
422
427
pub hooks : RpcHooks < Node , EthB :: EthApi > ,
@@ -426,9 +431,14 @@ pub struct RpcAddOns<
426
431
engine_validator_builder : EV ,
427
432
/// Builder for `EngineApi`
428
433
engine_api_builder : EB ,
434
+ /// Configurable RPC middleware stack.
435
+ ///
436
+ /// This middleware is applied to all RPC requests across all transports (HTTP, WS, IPC).
437
+ /// See [`RpcAddOns::with_rpc_middleware`] for more details.
438
+ rpc_middleware : RpcServiceBuilder < RpcMiddleware > ,
429
439
}
430
440
431
- impl < Node , EthB , EV , EB > Debug for RpcAddOns < Node , EthB , EV , EB >
441
+ impl < Node , EthB , EV , EB , RpcMiddleware > Debug for RpcAddOns < Node , EthB , EV , EB , RpcMiddleware >
432
442
where
433
443
Node : FullNodeComponents ,
434
444
EthB : EthApiBuilder < Node > ,
@@ -441,11 +451,12 @@ where
441
451
. field ( "eth_api_builder" , & "..." )
442
452
. field ( "engine_validator_builder" , & self . engine_validator_builder )
443
453
. field ( "engine_api_builder" , & self . engine_api_builder )
454
+ . field ( "rpc_middleware" , & "..." )
444
455
. finish ( )
445
456
}
446
457
}
447
458
448
- impl < Node , EthB , EV , EB > RpcAddOns < Node , EthB , EV , EB >
459
+ impl < Node , EthB , EV , EB , RpcMiddleware > RpcAddOns < Node , EthB , EV , EB , RpcMiddleware >
449
460
where
450
461
Node : FullNodeComponents ,
451
462
EthB : EthApiBuilder < Node > ,
@@ -455,28 +466,98 @@ where
455
466
eth_api_builder : EthB ,
456
467
engine_validator_builder : EV ,
457
468
engine_api_builder : EB ,
469
+ rpc_middleware : RpcServiceBuilder < RpcMiddleware > ,
458
470
) -> Self {
459
471
Self {
460
472
hooks : RpcHooks :: default ( ) ,
461
473
eth_api_builder,
462
474
engine_validator_builder,
463
475
engine_api_builder,
476
+ rpc_middleware,
464
477
}
465
478
}
466
479
467
480
/// Maps the [`EngineApiBuilder`] builder type.
468
- pub fn with_engine_api < T > ( self , engine_api_builder : T ) -> RpcAddOns < Node , EthB , EV , T > {
469
- let Self { hooks, eth_api_builder, engine_validator_builder, .. } = self ;
470
- RpcAddOns { hooks, eth_api_builder, engine_validator_builder, engine_api_builder }
481
+ pub fn with_engine_api < T > (
482
+ self ,
483
+ engine_api_builder : T ,
484
+ ) -> RpcAddOns < Node , EthB , EV , T , RpcMiddleware > {
485
+ let Self { hooks, eth_api_builder, engine_validator_builder, rpc_middleware, .. } = self ;
486
+ RpcAddOns {
487
+ hooks,
488
+ eth_api_builder,
489
+ engine_validator_builder,
490
+ engine_api_builder,
491
+ rpc_middleware,
492
+ }
471
493
}
472
494
473
495
/// Maps the [`EngineValidatorBuilder`] builder type.
474
496
pub fn with_engine_validator < T > (
475
497
self ,
476
498
engine_validator_builder : T ,
477
- ) -> RpcAddOns < Node , EthB , T , EB > {
478
- let Self { hooks, eth_api_builder, engine_api_builder, .. } = self ;
479
- RpcAddOns { hooks, eth_api_builder, engine_validator_builder, engine_api_builder }
499
+ ) -> RpcAddOns < Node , EthB , T , EB , RpcMiddleware > {
500
+ let Self { hooks, eth_api_builder, engine_api_builder, rpc_middleware, .. } = self ;
501
+ RpcAddOns {
502
+ hooks,
503
+ eth_api_builder,
504
+ engine_validator_builder,
505
+ engine_api_builder,
506
+ rpc_middleware,
507
+ }
508
+ }
509
+
510
+ /// Sets the RPC middleware stack for processing RPC requests.
511
+ ///
512
+ /// This method configures a custom middleware stack that will be applied to all RPC requests
513
+ /// across HTTP, `WebSocket`, and IPC transports. The middleware is applied to the RPC service
514
+ /// layer, allowing you to intercept, modify, or enhance RPC request processing.
515
+ ///
516
+ ///
517
+ /// # How It Works
518
+ ///
519
+ /// The middleware uses the Tower ecosystem's `Layer` pattern. When an RPC server is started,
520
+ /// the configured middleware stack is applied to create a layered service that processes
521
+ /// requests in the order the layers were added.
522
+ ///
523
+ /// # Examples
524
+ ///
525
+ /// ```ignore
526
+ /// use reth_rpc_builder::{RpcServiceBuilder, RpcRequestMetrics};
527
+ /// use tower::Layer;
528
+ ///
529
+ /// // Simple example with metrics
530
+ /// let metrics_layer = RpcRequestMetrics::new(metrics_recorder);
531
+ /// let with_metrics = rpc_addons.with_rpc_middleware(
532
+ /// RpcServiceBuilder::new().layer(metrics_layer)
533
+ /// );
534
+ ///
535
+ /// // Composing multiple middleware layers
536
+ /// let middleware_stack = RpcServiceBuilder::new()
537
+ /// .layer(rate_limit_layer)
538
+ /// .layer(logging_layer)
539
+ /// .layer(metrics_layer);
540
+ /// let with_full_stack = rpc_addons.with_rpc_middleware(middleware_stack);
541
+ /// ```
542
+ ///
543
+ /// # Notes
544
+ ///
545
+ /// - Middleware is applied to the RPC service layer, not the HTTP transport layer
546
+ /// - The default middleware is `Identity` (no-op), which passes through requests unchanged
547
+ /// - Middleware layers are applied in the order they are added via `.layer()`
548
+ pub fn with_rpc_middleware < T > (
549
+ self ,
550
+ rpc_middleware : RpcServiceBuilder < T > ,
551
+ ) -> RpcAddOns < Node , EthB , EV , EB , T > {
552
+ let Self { hooks, eth_api_builder, engine_validator_builder, engine_api_builder, .. } =
553
+ self ;
554
+ RpcAddOns {
555
+ hooks,
556
+ eth_api_builder,
557
+ engine_validator_builder,
558
+ engine_api_builder,
559
+ rpc_middleware,
560
+ }
480
561
}
481
562
482
563
/// Sets the hook that is run once the rpc server is started.
@@ -500,25 +581,35 @@ where
500
581
}
501
582
}
502
583
503
- impl < Node , EthB , EV , EB > Default for RpcAddOns < Node , EthB , EV , EB >
584
+ impl < Node , EthB , EV , EB > Default for RpcAddOns < Node , EthB , EV , EB , Identity >
504
585
where
505
586
Node : FullNodeComponents ,
506
587
EthB : EthApiBuilder < Node > ,
507
588
EV : Default ,
508
589
EB : Default ,
509
590
{
510
591
fn default ( ) -> Self {
511
- Self :: new ( EthB :: default ( ) , EV :: default ( ) , EB :: default ( ) )
592
+ Self :: new ( EthB :: default ( ) , EV :: default ( ) , EB :: default ( ) , RpcServiceBuilder :: new ( ) )
512
593
}
513
594
}
514
595
515
- impl < N , EthB , EV , EB > RpcAddOns < N , EthB , EV , EB >
596
+ impl < N , EthB , EV , EB , RpcMiddleware > RpcAddOns < N , EthB , EV , EB , RpcMiddleware >
516
597
where
517
598
N : FullNodeComponents ,
518
599
N :: Provider : ChainSpecProvider < ChainSpec : EthereumHardforks > ,
519
600
EthB : EthApiBuilder < N > ,
520
601
EV : EngineValidatorBuilder < N > ,
521
602
EB : EngineApiBuilder < N > ,
603
+ RpcMiddleware : Layer < RpcRequestMetricsService < RpcService > > + Clone + Send + ' static ,
604
+ <RpcMiddleware as Layer < RpcRequestMetricsService < RpcService > > >:: Service :
605
+ Send
606
+ + Sync
607
+ + ' static
608
+ + jsonrpsee:: server:: middleware:: rpc:: RpcServiceT <
609
+ MethodResponse = jsonrpsee:: MethodResponse ,
610
+ BatchResponse = jsonrpsee:: MethodResponse ,
611
+ NotificationResponse = jsonrpsee:: MethodResponse ,
612
+ > ,
522
613
{
523
614
/// Launches only the regular RPC server (HTTP/WS/IPC), without the authenticated Engine API
524
615
/// server.
@@ -533,6 +624,7 @@ where
533
624
where
534
625
F : FnOnce ( RpcModuleContainer < ' _ , N , EthB :: EthApi > ) -> eyre:: Result < ( ) > ,
535
626
{
627
+ let rpc_middleware = self . rpc_middleware . clone ( ) ;
536
628
let setup_ctx = self . setup_rpc_components ( ctx, ext) . await ?;
537
629
let RpcSetupContext {
538
630
node,
@@ -546,7 +638,7 @@ where
546
638
engine_handle,
547
639
} = setup_ctx;
548
640
549
- let server_config = config. rpc . rpc_server_config ( ) ;
641
+ let server_config = config. rpc . rpc_server_config ( ) . set_rpc_middleware ( rpc_middleware ) ;
550
642
let rpc_server_handle = Self :: launch_rpc_server_internal ( server_config, & modules) . await ?;
551
643
552
644
let handles =
@@ -579,6 +671,7 @@ where
579
671
where
580
672
F : FnOnce ( RpcModuleContainer < ' _ , N , EthB :: EthApi > ) -> eyre:: Result < ( ) > ,
581
673
{
674
+ let rpc_middleware = self . rpc_middleware . clone ( ) ;
582
675
let setup_ctx = self . setup_rpc_components ( ctx, ext) . await ?;
583
676
let RpcSetupContext {
584
677
node,
@@ -592,7 +685,7 @@ where
592
685
engine_handle,
593
686
} = setup_ctx;
594
687
595
- let server_config = config. rpc . rpc_server_config ( ) ;
688
+ let server_config = config. rpc . rpc_server_config ( ) . set_rpc_middleware ( rpc_middleware ) ;
596
689
let auth_module_clone = auth_module. clone ( ) ;
597
690
598
691
// launch servers concurrently
@@ -706,10 +799,22 @@ where
706
799
}
707
800
708
801
/// Helper to launch the RPC server
709
- async fn launch_rpc_server_internal (
710
- server_config : RpcServerConfig ,
802
+ async fn launch_rpc_server_internal < M > (
803
+ server_config : RpcServerConfig < M > ,
711
804
modules : & TransportRpcModules ,
712
- ) -> eyre:: Result < RpcServerHandle > {
805
+ ) -> eyre:: Result < RpcServerHandle >
806
+ where
807
+ M : Layer < RpcRequestMetricsService < RpcService > > + Clone + Send + ' static ,
808
+ for < ' a > <M as Layer < RpcRequestMetricsService < RpcService > > >:: Service :
809
+ Send
810
+ + Sync
811
+ + ' static
812
+ + jsonrpsee:: server:: middleware:: rpc:: RpcServiceT <
813
+ MethodResponse = jsonrpsee:: MethodResponse ,
814
+ BatchResponse = jsonrpsee:: MethodResponse ,
815
+ NotificationResponse = jsonrpsee:: MethodResponse ,
816
+ > ,
817
+ {
713
818
let handle = server_config. start ( modules) . await ?;
714
819
715
820
if let Some ( path) = handle. ipc_endpoint ( ) {
@@ -760,13 +865,23 @@ where
760
865
}
761
866
}
762
867
763
- impl < N , EthB , EV , EB > NodeAddOns < N > for RpcAddOns < N , EthB , EV , EB >
868
+ impl < N , EthB , EV , EB , RpcMiddleware > NodeAddOns < N > for RpcAddOns < N , EthB , EV , EB , RpcMiddleware >
764
869
where
765
870
N : FullNodeComponents ,
766
871
<N as FullNodeTypes >:: Provider : ChainSpecProvider < ChainSpec : EthereumHardforks > ,
767
872
EthB : EthApiBuilder < N > ,
768
873
EV : EngineValidatorBuilder < N > ,
769
874
EB : EngineApiBuilder < N > ,
875
+ RpcMiddleware : Layer < RpcRequestMetricsService < RpcService > > + Clone + Send + ' static ,
876
+ <RpcMiddleware as Layer < RpcRequestMetricsService < RpcService > > >:: Service :
877
+ Send
878
+ + Sync
879
+ + ' static
880
+ + jsonrpsee:: server:: middleware:: rpc:: RpcServiceT <
881
+ MethodResponse = jsonrpsee:: MethodResponse ,
882
+ BatchResponse = jsonrpsee:: MethodResponse ,
883
+ NotificationResponse = jsonrpsee:: MethodResponse ,
884
+ > ,
770
885
{
771
886
type Handle = RpcHandle < N , EthB :: EthApi > ;
772
887
@@ -787,7 +902,8 @@ pub trait RethRpcAddOns<N: FullNodeComponents>:
787
902
fn hooks_mut ( & mut self ) -> & mut RpcHooks < N , Self :: EthApi > ;
788
903
}
789
904
790
- impl < N : FullNodeComponents , EthB , EV , EB > RethRpcAddOns < N > for RpcAddOns < N , EthB , EV , EB >
905
+ impl < N : FullNodeComponents , EthB , EV , EB , RpcMiddleware > RethRpcAddOns < N >
906
+ for RpcAddOns < N , EthB , EV , EB , RpcMiddleware >
791
907
where
792
908
Self : NodeAddOns < N , Handle = RpcHandle < N , EthB :: EthApi > > ,
793
909
EthB : EthApiBuilder < N > ,
0 commit comments