Skip to content

Commit 6ea2e32

Browse files
committed
Handle Inconsistent Response in Miner Api
1 parent 599f1a8 commit 6ea2e32

3 files changed

Lines changed: 93 additions & 32 deletions

File tree

src/cli.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use std::{net::SocketAddr, path::PathBuf};
1+
use std::{net::SocketAddr, path::PathBuf, sync::Arc};
22

33
use alloy_rpc_types_engine::JwtSecret;
44
use clap::{Parser, Subcommand};
55
use eyre::bail;
66
use jsonrpsee::{RpcModule, server::Server};
7+
use parking_lot::Mutex;
78
use tokio::signal::unix::{SignalKind, signal as unix_signal};
89
use tracing::{Level, info};
910

@@ -157,11 +158,12 @@ impl Args {
157158

158159
let (probe_layer, probes) = ProbeLayer::new();
159160

161+
let execution_mode = Arc::new(Mutex::new(self.execution_mode));
160162
let rollup_boost = RollupBoostServer::new(
161163
l2_client,
162164
builder_client,
163-
self.execution_mode,
164-
probes,
165+
execution_mode.clone(),
166+
probes.clone(),
165167
self.health_check_interval,
166168
self.max_unsafe_interval,
167169
);
@@ -182,6 +184,8 @@ impl Args {
182184
l2_auth_jwt,
183185
builder_args.builder_url,
184186
builder_auth_jwt,
187+
probes,
188+
execution_mode,
185189
));
186190

187191
let server = Server::builder()

src/proxy.rs

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
use crate::client::http::HttpClient;
22
use crate::server::PayloadSource;
3+
use crate::{ExecutionMode, Health, Probes};
34
use alloy_rpc_types_engine::JwtSecret;
45
use http::Uri;
56
use jsonrpsee::core::{BoxError, http_helpers};
67
use jsonrpsee::http_client::{HttpBody, HttpRequest, HttpResponse};
8+
use parking_lot::Mutex;
9+
use std::sync::Arc;
710
use std::task::{Context, Poll};
811
use std::{future::Future, pin::Pin};
912
use tower::{Layer, Service};
10-
use tracing::info;
13+
use tracing::{error, info, warn};
1114

1215
const 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

3242
impl 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);

src/server.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl RollupBoostServer {
134134
pub fn new(
135135
l2_client: RpcClient,
136136
builder_client: RpcClient,
137-
initial_execution_mode: ExecutionMode,
137+
initial_execution_mode: Arc<Mutex<ExecutionMode>>,
138138
probes: Arc<Probes>,
139139
health_check_interval: u64,
140140
max_unsafe_interval: u64,
@@ -151,7 +151,7 @@ impl RollupBoostServer {
151151
l2_client: Arc::new(l2_client),
152152
builder_client: Arc::new(builder_client),
153153
payload_trace_context: Arc::new(PayloadTraceContext::new()),
154-
execution_mode: Arc::new(Mutex::new(initial_execution_mode)),
154+
execution_mode: initial_execution_mode,
155155
probes,
156156
health_handle,
157157
}
@@ -808,12 +808,13 @@ mod tests {
808808
.unwrap();
809809

810810
let (probe_layer, probes) = ProbeLayer::new();
811+
let execution_mode = Arc::new(Mutex::new(ExecutionMode::Enabled));
811812

812813
let rollup_boost = RollupBoostServer::new(
813814
l2_client,
814815
builder_client,
815-
ExecutionMode::Enabled,
816-
probes,
816+
execution_mode.clone(),
817+
probes.clone(),
817818
60,
818819
5,
819820
);
@@ -828,6 +829,8 @@ mod tests {
828829
jwt_secret,
829830
builder_auth_rpc,
830831
jwt_secret,
832+
probes,
833+
execution_mode.clone(),
831834
));
832835

833836
let server = Server::builder()

0 commit comments

Comments
 (0)