11use crate :: client:: http:: HttpClient ;
22use crate :: server:: PayloadSource ;
3+ use crate :: { ExecutionMode , Health , Probes } ;
34use alloy_rpc_types_engine:: JwtSecret ;
45use http:: Uri ;
56use jsonrpsee:: core:: { BoxError , http_helpers} ;
67use jsonrpsee:: http_client:: { HttpBody , HttpRequest , HttpResponse } ;
8+ use parking_lot:: Mutex ;
9+ use std:: sync:: Arc ;
710use std:: task:: { Context , Poll } ;
811use std:: { future:: Future , pin:: Pin } ;
912use tower:: { Layer , Service } ;
10- use tracing:: info;
13+ use tracing:: { error , info, warn } ;
1114
1215const ENGINE_METHOD : & str = "engine_" ;
1316
1417/// Requests that should be forwarded to both the builder and default execution client
15- const FORWARD_REQUESTS : [ & str ; 6 ] = [
18+ const FORWARD_REQUESTS : [ & str ; 2 ] = [
1619 "eth_sendRawTransaction" ,
1720 "eth_sendRawTransactionConditional" ,
21+ ] ;
22+
23+ /// Handle these similar to FORWARD_REQUESTS, but enforce consistant responses
24+ /// between the builder and default execution client.
25+ const MINER_REQUESTS : [ & str ; 4 ] = [
1826 "miner_setExtra" ,
1927 "miner_setGasPrice" ,
2028 "miner_setGasLimit" ,
@@ -27,6 +35,8 @@ pub struct ProxyLayer {
2735 l2_auth_secret : JwtSecret ,
2836 builder_auth_rpc : Uri ,
2937 builder_auth_secret : JwtSecret ,
38+ probes : Arc < Probes > ,
39+ execution_mode : Arc < Mutex < ExecutionMode > > ,
3040}
3141
3242impl ProxyLayer {
@@ -35,12 +45,16 @@ impl ProxyLayer {
3545 l2_auth_secret : JwtSecret ,
3646 builder_auth_rpc : Uri ,
3747 builder_auth_secret : JwtSecret ,
48+ probes : Arc < Probes > ,
49+ execution_mode : Arc < Mutex < ExecutionMode > > ,
3850 ) -> Self {
3951 ProxyLayer {
4052 l2_auth_rpc,
4153 l2_auth_secret,
4254 builder_auth_rpc,
4355 builder_auth_secret,
56+ probes,
57+ execution_mode,
4458 }
4559 }
4660}
@@ -65,6 +79,8 @@ impl<S> Layer<S> for ProxyLayer {
6579 inner,
6680 l2_client,
6781 builder_client,
82+ probes : self . probes . clone ( ) ,
83+ execution_mode : self . execution_mode . clone ( ) ,
6884 }
6985 }
7086}
@@ -74,6 +90,8 @@ pub struct ProxyService<S> {
7490 inner : S ,
7591 l2_client : HttpClient ,
7692 builder_client : HttpClient ,
93+ probes : Arc < Probes > ,
94+ execution_mode : Arc < Mutex < ExecutionMode > > ,
7795}
7896
7997// Consider using `RpcServiceT` when https://github.com/paritytech/jsonrpsee/pull/1521 is merged
@@ -131,8 +149,32 @@ where
131149 } ) ;
132150
133151 let l2_req = HttpRequest :: from_parts ( parts, HttpBody :: from ( body_bytes) ) ;
134- info ! ( target: "proxy::call" , message = "forward request to default execution client" , ?method) ;
135152 service. l2_client . forward ( l2_req, method) . await
153+ } else if MINER_REQUESTS . contains ( & method. as_str ( ) ) {
154+ // miner api, send to both the
155+ // default execution client and the builder
156+ let builder_req =
157+ HttpRequest :: from_parts ( parts. clone ( ) , HttpBody :: from ( body_bytes. clone ( ) ) ) ;
158+ let builder_method = method. clone ( ) ;
159+ let mut builder_client = service. builder_client . clone ( ) ;
160+
161+ let l2_req = HttpRequest :: from_parts ( parts, HttpBody :: from ( body_bytes) ) ;
162+ let ( builder_res, l2_res) = tokio:: join!(
163+ builder_client. forward( builder_req, builder_method) ,
164+ service. l2_client. forward( l2_req, method)
165+ ) ;
166+ if builder_res. is_ok ( ) != l2_res. is_ok ( ) {
167+ error ! ( target: "proxy::call" , message = "inconsistent miner api responses from builder and L2" ) ;
168+ let mut execution_mode = service. execution_mode . lock ( ) ;
169+ if * execution_mode == ExecutionMode :: Enabled {
170+ * execution_mode = ExecutionMode :: Disabled ;
171+ // Drop before aquiring health lock
172+ drop ( execution_mode) ;
173+ warn ! ( target: "proxy::call" , message = "setting execution mode to Fallback" ) ;
174+ service. probes . set_health ( Health :: PartialContent ) ;
175+ }
176+ }
177+ l2_res
136178 } else {
137179 // If the request should not be forwarded, send directly to the
138180 // default execution client
@@ -172,7 +214,7 @@ mod tests {
172214 use std:: {
173215 net:: { IpAddr , SocketAddr } ,
174216 str:: FromStr ,
175- sync:: { Arc , Mutex } ,
217+ sync:: Arc ,
176218 } ;
177219 use tokio:: net:: TcpListener ;
178220 use tokio:: task:: JoinHandle ;
@@ -198,12 +240,15 @@ mod tests {
198240 async fn new ( ) -> eyre:: Result < Self > {
199241 let builder = MockHttpServer :: serve ( ) . await ?;
200242 let l2 = MockHttpServer :: serve ( ) . await ?;
243+ let execution_mode = Arc :: new ( Mutex :: new ( ExecutionMode :: Enabled ) ) ;
244+ let probes = Arc :: new ( Probes :: default ( ) ) ;
201245 let middleware = tower:: ServiceBuilder :: new ( ) . layer ( ProxyLayer :: new (
202246 format ! ( "http://{}:{}" , l2. addr. ip( ) , l2. addr. port( ) ) . parse :: < Uri > ( ) ?,
203247 JwtSecret :: random ( ) ,
204248 format ! ( "http://{}:{}" , builder. addr. ip( ) , builder. addr. port( ) ) . parse :: < Uri > ( ) ?,
205249 JwtSecret :: random ( ) ,
206- // None,
250+ probes. clone ( ) ,
251+ execution_mode. clone ( ) ,
207252 ) ) ;
208253
209254 let temp_listener = TcpListener :: bind ( "0.0.0.0:0" ) . await ?;
@@ -313,7 +358,7 @@ mod tests {
313358 }
314359 } ;
315360
316- requests. lock ( ) . unwrap ( ) . push ( request_body. clone ( ) ) ;
361+ requests. lock ( ) . push ( request_body. clone ( ) ) ;
317362
318363 let method = request_body[ "method" ] . as_str ( ) . unwrap_or_default ( ) ;
319364
@@ -391,7 +436,8 @@ mod tests {
391436 }
392437
393438 async fn health_check ( ) {
394- let proxy_server = spawn_proxy_server ( ) . await ;
439+ let execution_mode = Arc :: new ( Mutex :: new ( ExecutionMode :: Enabled ) ) ;
440+ let proxy_server = spawn_proxy_server ( execution_mode) . await ;
395441 // Create a new HTTP client
396442 let client: Client < HttpConnector , HttpBody > =
397443 Client :: builder ( TokioExecutor :: new ( ) ) . build_http ( ) ;
@@ -408,8 +454,9 @@ mod tests {
408454 }
409455
410456 async fn send_request ( method : & str ) -> Result < String , ClientError > {
457+ let execution_mode = Arc :: new ( Mutex :: new ( ExecutionMode :: Enabled ) ) ;
411458 let server = spawn_server ( ) . await ;
412- let proxy_server = spawn_proxy_server ( ) . await ;
459+ let proxy_server = spawn_proxy_server ( execution_mode ) . await ;
413460 let proxy_client = HttpClient :: builder ( )
414461 . build ( format ! ( "http://{ADDR}:{PORT}" ) )
415462 . unwrap ( ) ;
@@ -446,7 +493,7 @@ mod tests {
446493 }
447494
448495 /// Spawn a new RPC server with a proxy layer.
449- async fn spawn_proxy_server ( ) -> ServerHandle {
496+ async fn spawn_proxy_server ( execution_mode : Arc < Mutex < ExecutionMode > > ) -> ServerHandle {
450497 let addr = format ! ( "{ADDR}:{PORT}" ) ;
451498
452499 let jwt = JwtSecret :: random ( ) ;
@@ -457,9 +504,16 @@ mod tests {
457504 . parse :: < Uri > ( )
458505 . unwrap ( ) ;
459506
460- let ( probe_layer, _probes ) = ProbeLayer :: new ( ) ;
507+ let ( probe_layer, probes ) = ProbeLayer :: new ( ) ;
461508
462- let proxy_layer = ProxyLayer :: new ( l2_auth_uri. clone ( ) , jwt, l2_auth_uri, jwt) ;
509+ let proxy_layer = ProxyLayer :: new (
510+ l2_auth_uri. clone ( ) ,
511+ jwt,
512+ l2_auth_uri,
513+ jwt,
514+ probes,
515+ execution_mode,
516+ ) ;
463517
464518 // Create a layered server
465519 let server = ServerBuilder :: default ( )
@@ -509,7 +563,7 @@ mod tests {
509563
510564 // Assert the builder received the correct payload
511565 let builder = & test_harness. builder ;
512- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
566+ let builder_requests = builder. requests . lock ( ) ;
513567 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
514568 assert_eq ! ( builder_requests. len( ) , 1 ) ;
515569 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
@@ -518,7 +572,7 @@ mod tests {
518572
519573 // Assert the l2 received the correct payload
520574 let l2 = & test_harness. l2 ;
521- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
575+ let l2_requests = l2. requests . lock ( ) ;
522576 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
523577 assert_eq ! ( l2_requests. len( ) , 1 ) ;
524578 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -545,15 +599,15 @@ mod tests {
545599
546600 // Assert the builder received the correct payload
547601 let builder = & test_harness. builder ;
548- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
602+ let builder_requests = builder. requests . lock ( ) ;
549603 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
550604 assert_eq ! ( builder_requests. len( ) , 1 ) ;
551605 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
552606 assert_eq ! ( builder_req[ "params" ] [ 0 ] , expected_tx) ;
553607
554608 // Assert the l2 received the correct payload
555609 let l2 = & test_harness. l2 ;
556- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
610+ let l2_requests = l2. requests . lock ( ) ;
557611 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
558612 assert_eq ! ( l2_requests. len( ) , 1 ) ;
559613 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -582,7 +636,7 @@ mod tests {
582636 let expected_conditionals = json ! ( transact_conditionals) ;
583637 // Assert the builder received the correct payload
584638 let builder = & test_harness. builder ;
585- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
639+ let builder_requests = builder. requests . lock ( ) ;
586640 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
587641 assert_eq ! ( builder_requests. len( ) , 1 ) ;
588642 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
@@ -591,7 +645,7 @@ mod tests {
591645
592646 // Assert the l2 received the correct payload
593647 let l2 = & test_harness. l2 ;
594- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
648+ let l2_requests = l2. requests . lock ( ) ;
595649 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
596650 assert_eq ! ( l2_requests. len( ) , 1 ) ;
597651 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -618,15 +672,15 @@ mod tests {
618672
619673 // Assert the builder received the correct payload
620674 let builder = & test_harness. builder ;
621- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
675+ let builder_requests = builder. requests . lock ( ) ;
622676 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
623677 assert_eq ! ( builder_requests. len( ) , 1 ) ;
624678 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
625679 assert_eq ! ( builder_req[ "params" ] [ 0 ] , expected_extra) ;
626680
627681 // Assert the l2 received the correct payload
628682 let l2 = & test_harness. l2 ;
629- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
683+ let l2_requests = l2. requests . lock ( ) ;
630684 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
631685 assert_eq ! ( l2_requests. len( ) , 1 ) ;
632686 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -652,15 +706,15 @@ mod tests {
652706
653707 // Assert the builder received the correct payload
654708 let builder = & test_harness. builder ;
655- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
709+ let builder_requests = builder. requests . lock ( ) ;
656710 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
657711 assert_eq ! ( builder_requests. len( ) , 1 ) ;
658712 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
659713 assert_eq ! ( builder_req[ "params" ] [ 0 ] , expected_price) ;
660714
661715 // Assert the l2 received the correct payload
662716 let l2 = & test_harness. l2 ;
663- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
717+ let l2_requests = l2. requests . lock ( ) ;
664718 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
665719 assert_eq ! ( l2_requests. len( ) , 1 ) ;
666720 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -687,15 +741,15 @@ mod tests {
687741
688742 // Assert the builder received the correct payload
689743 let builder = & test_harness. builder ;
690- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
744+ let builder_requests = builder. requests . lock ( ) ;
691745 let builder_req = builder_requests. first ( ) . unwrap ( ) ;
692746 assert_eq ! ( builder_requests. len( ) , 1 ) ;
693747 assert_eq ! ( builder_req[ "method" ] , expected_method) ;
694748 assert_eq ! ( builder_req[ "params" ] [ 0 ] , expected_price) ;
695749
696750 // Assert the l2 received the correct payload
697751 let l2 = & test_harness. l2 ;
698- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
752+ let l2_requests = l2. requests . lock ( ) ;
699753 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
700754 assert_eq ! ( l2_requests. len( ) , 1 ) ;
701755 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
@@ -721,12 +775,12 @@ mod tests {
721775
722776 // Assert the builder has not received the payload
723777 let builder = & test_harness. builder ;
724- let builder_requests = builder. requests . lock ( ) . unwrap ( ) ;
778+ let builder_requests = builder. requests . lock ( ) ;
725779 assert_eq ! ( builder_requests. len( ) , 0 ) ;
726780
727781 // Assert the l2 auth received the correct payload
728782 let l2 = & test_harness. l2 ;
729- let l2_requests = l2. requests . lock ( ) . unwrap ( ) ;
783+ let l2_requests = l2. requests . lock ( ) ;
730784 let l2_req = l2_requests. first ( ) . unwrap ( ) ;
731785 assert_eq ! ( l2_requests. len( ) , 1 ) ;
732786 assert_eq ! ( l2_req[ "method" ] , expected_method) ;
0 commit comments