Skip to content

Commit 8a2b679

Browse files
committed
Handle Inconsistent Response in Miner Api
1 parent 6194d92 commit 8a2b679

File tree

3 files changed

+94
-33
lines changed

3 files changed

+94
-33
lines changed

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

@@ -166,12 +167,13 @@ impl Args {
166167

167168
let (probe_layer, probes) = ProbeLayer::new();
168169

170+
let execution_mode = Arc::new(Mutex::new(self.execution_mode));
169171
let rollup_boost = RollupBoostServer::new(
170172
l2_client,
171173
builder_client,
172174
boost_sync_enabled,
173-
self.execution_mode,
174-
probes,
175+
execution_mode.clone(),
176+
probes.clone(),
175177
self.health_check_interval,
176178
self.max_unsafe_interval,
177179
);
@@ -192,6 +194,8 @@ impl Args {
192194
l2_auth_jwt,
193195
builder_args.builder_url,
194196
builder_auth_jwt,
197+
probes,
198+
execution_mode,
195199
));
196200

197201
let server = Server::builder()

src/proxy.rs

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
use crate::client::http::HttpClient;
2-
use crate::server::PayloadSource;
2+
use crate::server::{ExecutionMode, PayloadSource};
3+
use crate::{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 tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
1013
use tokio::sync::oneshot;
1114
use tower::{Layer, Service};
12-
use tracing::info;
15+
use tracing::{error, info, warn};
1316

1417
const ENGINE_METHOD: &str = "engine_";
1518

1619
/// Requests that should be forwarded to both the builder and default execution client
17-
const FORWARD_REQUESTS: [&str; 6] = [
20+
const FORWARD_REQUESTS: [&str; 2] = [
1821
"eth_sendRawTransaction",
1922
"eth_sendRawTransactionConditional",
23+
];
24+
25+
/// Handle these similar to FORWARD_REQUESTS, but enforce consistant responses
26+
/// between the builder and default execution client.
27+
const MINER_REQUESTS: [&str; 4] = [
2028
"miner_setExtra",
2129
"miner_setGasPrice",
2230
"miner_setGasLimit",
@@ -29,6 +37,8 @@ pub struct ProxyLayer {
2937
l2_auth_secret: JwtSecret,
3038
builder_auth_rpc: Uri,
3139
builder_auth_secret: JwtSecret,
40+
probes: Arc<Probes>,
41+
execution_mode: Arc<Mutex<ExecutionMode>>,
3242
}
3343

3444
impl ProxyLayer {
@@ -37,12 +47,16 @@ impl ProxyLayer {
3747
l2_auth_secret: JwtSecret,
3848
builder_auth_rpc: Uri,
3949
builder_auth_secret: JwtSecret,
50+
probes: Arc<Probes>,
51+
execution_mode: Arc<Mutex<ExecutionMode>>,
4052
) -> Self {
4153
ProxyLayer {
4254
l2_auth_rpc,
4355
l2_auth_secret,
4456
builder_auth_rpc,
4557
builder_auth_secret,
58+
probes,
59+
execution_mode,
4660
}
4761
}
4862
}
@@ -75,6 +89,8 @@ where
7589
l2_client,
7690
builder_client,
7791
engine_tx: tx,
92+
probes: self.probes.clone(),
93+
execution_mode: self.execution_mode.clone(),
7894
};
7995

8096
service.process_engine_queue(rx);
@@ -98,6 +114,8 @@ pub struct ProxyService<S> {
98114
l2_client: HttpClient,
99115
builder_client: HttpClient,
100116
engine_tx: EngineResponseTx,
117+
probes: Arc<Probes>,
118+
execution_mode: Arc<Mutex<ExecutionMode>>,
101119
}
102120

103121
impl<S> ProxyService<S>
@@ -179,8 +197,32 @@ where
179197
});
180198

181199
let l2_req = HttpRequest::from_parts(parts, HttpBody::from(body_bytes));
182-
info!(target: "proxy::call", message = "forward request to default execution client", ?method);
183200
service.l2_client.forward(l2_req, method).await
201+
} else if MINER_REQUESTS.contains(&method.as_str()) {
202+
// miner api, send to both the
203+
// default execution client and the builder
204+
let builder_req =
205+
HttpRequest::from_parts(parts.clone(), HttpBody::from(body_bytes.clone()));
206+
let builder_method = method.clone();
207+
let mut builder_client = service.builder_client.clone();
208+
209+
let l2_req = HttpRequest::from_parts(parts, HttpBody::from(body_bytes));
210+
let (builder_res, l2_res) = tokio::join!(
211+
builder_client.forward(builder_req, builder_method),
212+
service.l2_client.forward(l2_req, method)
213+
);
214+
if builder_res.is_ok() != l2_res.is_ok() {
215+
error!(target: "proxy::call", message = "inconsistent miner api responses from builder and L2");
216+
let mut execution_mode = service.execution_mode.lock();
217+
if *execution_mode == ExecutionMode::Enabled {
218+
*execution_mode = ExecutionMode::Fallback;
219+
// Drop before aquiring health lock
220+
drop(execution_mode);
221+
warn!(target: "proxy::call", message = "setting execution mode to Fallback");
222+
service.probes.set_health(Health::PartialContent);
223+
}
224+
}
225+
l2_res
184226
} else {
185227
// If the request should not be forwarded, send directly to the
186228
// default execution client
@@ -220,7 +262,7 @@ mod tests {
220262
use std::{
221263
net::{IpAddr, SocketAddr},
222264
str::FromStr,
223-
sync::{Arc, Mutex},
265+
sync::Arc,
224266
};
225267
use tokio::net::TcpListener;
226268
use tokio::task::JoinHandle;
@@ -246,12 +288,15 @@ mod tests {
246288
async fn new() -> eyre::Result<Self> {
247289
let builder = MockHttpServer::serve().await?;
248290
let l2 = MockHttpServer::serve().await?;
291+
let execution_mode = Arc::new(Mutex::new(ExecutionMode::Enabled));
292+
let probes = Arc::new(Probes::default());
249293
let middleware = tower::ServiceBuilder::new().layer(ProxyLayer::new(
250294
format!("http://{}:{}", l2.addr.ip(), l2.addr.port()).parse::<Uri>()?,
251295
JwtSecret::random(),
252296
format!("http://{}:{}", builder.addr.ip(), builder.addr.port()).parse::<Uri>()?,
253297
JwtSecret::random(),
254-
// None,
298+
probes.clone(),
299+
execution_mode.clone(),
255300
));
256301

257302
let temp_listener = TcpListener::bind("0.0.0.0:0").await?;
@@ -361,7 +406,7 @@ mod tests {
361406
}
362407
};
363408

364-
requests.lock().unwrap().push(request_body.clone());
409+
requests.lock().push(request_body.clone());
365410

366411
let method = request_body["method"].as_str().unwrap_or_default();
367412

@@ -439,7 +484,8 @@ mod tests {
439484
}
440485

441486
async fn health_check() {
442-
let proxy_server = spawn_proxy_server().await;
487+
let execution_mode = Arc::new(Mutex::new(ExecutionMode::Enabled));
488+
let proxy_server = spawn_proxy_server(execution_mode).await;
443489
// Create a new HTTP client
444490
let client: Client<HttpConnector, HttpBody> =
445491
Client::builder(TokioExecutor::new()).build_http();
@@ -456,8 +502,9 @@ mod tests {
456502
}
457503

458504
async fn send_request(method: &str) -> Result<String, ClientError> {
505+
let execution_mode = Arc::new(Mutex::new(ExecutionMode::Enabled));
459506
let server = spawn_server().await;
460-
let proxy_server = spawn_proxy_server().await;
507+
let proxy_server = spawn_proxy_server(execution_mode).await;
461508
let proxy_client = HttpClient::builder()
462509
.build(format!("http://{ADDR}:{PORT}"))
463510
.unwrap();
@@ -494,7 +541,7 @@ mod tests {
494541
}
495542

496543
/// Spawn a new RPC server with a proxy layer.
497-
async fn spawn_proxy_server() -> ServerHandle {
544+
async fn spawn_proxy_server(execution_mode: Arc<Mutex<ExecutionMode>>) -> ServerHandle {
498545
let addr = format!("{ADDR}:{PORT}");
499546

500547
let jwt = JwtSecret::random();
@@ -505,9 +552,16 @@ mod tests {
505552
.parse::<Uri>()
506553
.unwrap();
507554

508-
let (probe_layer, _probes) = ProbeLayer::new();
555+
let (probe_layer, probes) = ProbeLayer::new();
509556

510-
let proxy_layer = ProxyLayer::new(l2_auth_uri.clone(), jwt, l2_auth_uri, jwt);
557+
let proxy_layer = ProxyLayer::new(
558+
l2_auth_uri.clone(),
559+
jwt,
560+
l2_auth_uri,
561+
jwt,
562+
probes,
563+
execution_mode,
564+
);
511565

512566
// Create a layered server
513567
let server = ServerBuilder::default()
@@ -557,7 +611,7 @@ mod tests {
557611

558612
// Assert the builder received the correct payload
559613
let builder = &test_harness.builder;
560-
let builder_requests = builder.requests.lock().unwrap();
614+
let builder_requests = builder.requests.lock();
561615
let builder_req = builder_requests.first().unwrap();
562616
assert_eq!(builder_requests.len(), 1);
563617
assert_eq!(builder_req["method"], expected_method);
@@ -566,7 +620,7 @@ mod tests {
566620

567621
// Assert the l2 received the correct payload
568622
let l2 = &test_harness.l2;
569-
let l2_requests = l2.requests.lock().unwrap();
623+
let l2_requests = l2.requests.lock();
570624
let l2_req = l2_requests.first().unwrap();
571625
assert_eq!(l2_requests.len(), 1);
572626
assert_eq!(l2_req["method"], expected_method);
@@ -593,15 +647,15 @@ mod tests {
593647

594648
// Assert the builder received the correct payload
595649
let builder = &test_harness.builder;
596-
let builder_requests = builder.requests.lock().unwrap();
650+
let builder_requests = builder.requests.lock();
597651
let builder_req = builder_requests.first().unwrap();
598652
assert_eq!(builder_requests.len(), 1);
599653
assert_eq!(builder_req["method"], expected_method);
600654
assert_eq!(builder_req["params"][0], expected_tx);
601655

602656
// Assert the l2 received the correct payload
603657
let l2 = &test_harness.l2;
604-
let l2_requests = l2.requests.lock().unwrap();
658+
let l2_requests = l2.requests.lock();
605659
let l2_req = l2_requests.first().unwrap();
606660
assert_eq!(l2_requests.len(), 1);
607661
assert_eq!(l2_req["method"], expected_method);
@@ -630,7 +684,7 @@ mod tests {
630684
let expected_conditionals = json!(transact_conditionals);
631685
// Assert the builder received the correct payload
632686
let builder = &test_harness.builder;
633-
let builder_requests = builder.requests.lock().unwrap();
687+
let builder_requests = builder.requests.lock();
634688
let builder_req = builder_requests.first().unwrap();
635689
assert_eq!(builder_requests.len(), 1);
636690
assert_eq!(builder_req["method"], expected_method);
@@ -639,7 +693,7 @@ mod tests {
639693

640694
// Assert the l2 received the correct payload
641695
let l2 = &test_harness.l2;
642-
let l2_requests = l2.requests.lock().unwrap();
696+
let l2_requests = l2.requests.lock();
643697
let l2_req = l2_requests.first().unwrap();
644698
assert_eq!(l2_requests.len(), 1);
645699
assert_eq!(l2_req["method"], expected_method);
@@ -666,15 +720,15 @@ mod tests {
666720

667721
// Assert the builder received the correct payload
668722
let builder = &test_harness.builder;
669-
let builder_requests = builder.requests.lock().unwrap();
723+
let builder_requests = builder.requests.lock();
670724
let builder_req = builder_requests.first().unwrap();
671725
assert_eq!(builder_requests.len(), 1);
672726
assert_eq!(builder_req["method"], expected_method);
673727
assert_eq!(builder_req["params"][0], expected_extra);
674728

675729
// Assert the l2 received the correct payload
676730
let l2 = &test_harness.l2;
677-
let l2_requests = l2.requests.lock().unwrap();
731+
let l2_requests = l2.requests.lock();
678732
let l2_req = l2_requests.first().unwrap();
679733
assert_eq!(l2_requests.len(), 1);
680734
assert_eq!(l2_req["method"], expected_method);
@@ -700,15 +754,15 @@ mod tests {
700754

701755
// Assert the builder received the correct payload
702756
let builder = &test_harness.builder;
703-
let builder_requests = builder.requests.lock().unwrap();
757+
let builder_requests = builder.requests.lock();
704758
let builder_req = builder_requests.first().unwrap();
705759
assert_eq!(builder_requests.len(), 1);
706760
assert_eq!(builder_req["method"], expected_method);
707761
assert_eq!(builder_req["params"][0], expected_price);
708762

709763
// Assert the l2 received the correct payload
710764
let l2 = &test_harness.l2;
711-
let l2_requests = l2.requests.lock().unwrap();
765+
let l2_requests = l2.requests.lock();
712766
let l2_req = l2_requests.first().unwrap();
713767
assert_eq!(l2_requests.len(), 1);
714768
assert_eq!(l2_req["method"], expected_method);
@@ -735,15 +789,15 @@ mod tests {
735789

736790
// Assert the builder received the correct payload
737791
let builder = &test_harness.builder;
738-
let builder_requests = builder.requests.lock().unwrap();
792+
let builder_requests = builder.requests.lock();
739793
let builder_req = builder_requests.first().unwrap();
740794
assert_eq!(builder_requests.len(), 1);
741795
assert_eq!(builder_req["method"], expected_method);
742796
assert_eq!(builder_req["params"][0], expected_price);
743797

744798
// Assert the l2 received the correct payload
745799
let l2 = &test_harness.l2;
746-
let l2_requests = l2.requests.lock().unwrap();
800+
let l2_requests = l2.requests.lock();
747801
let l2_req = l2_requests.first().unwrap();
748802
assert_eq!(l2_requests.len(), 1);
749803
assert_eq!(l2_req["method"], expected_method);
@@ -769,12 +823,12 @@ mod tests {
769823

770824
// Assert the builder has not received the payload
771825
let builder = &test_harness.builder;
772-
let builder_requests = builder.requests.lock().unwrap();
826+
let builder_requests = builder.requests.lock();
773827
assert_eq!(builder_requests.len(), 0);
774828

775829
// Assert the l2 auth received the correct payload
776830
let l2 = &test_harness.l2;
777-
let l2_requests = l2.requests.lock().unwrap();
831+
let l2_requests = l2.requests.lock();
778832
let l2_req = l2_requests.first().unwrap();
779833
assert_eq!(l2_requests.len(), 1);
780834
assert_eq!(l2_req["method"], expected_method);

src/server.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl RollupBoostServer {
174174
l2_client: RpcClient,
175175
builder_client: RpcClient,
176176
boost_sync: bool,
177-
initial_execution_mode: ExecutionMode,
177+
initial_execution_mode: Arc<Mutex<ExecutionMode>>,
178178
probes: Arc<Probes>,
179179
health_check_interval: u64,
180180
max_unsafe_interval: u64,
@@ -192,7 +192,7 @@ impl RollupBoostServer {
192192
builder_client: Arc::new(builder_client),
193193
boost_sync,
194194
payload_trace_context: Arc::new(PayloadTraceContext::new()),
195-
execution_mode: Arc::new(Mutex::new(initial_execution_mode)),
195+
execution_mode: initial_execution_mode,
196196
probes,
197197
health_handle,
198198
}
@@ -824,13 +824,14 @@ mod tests {
824824
.unwrap();
825825

826826
let (probe_layer, probes) = ProbeLayer::new();
827+
let execution_mode = Arc::new(Mutex::new(ExecutionMode::Enabled));
827828

828829
let rollup_boost = RollupBoostServer::new(
829830
l2_client,
830831
builder_client,
831832
boost_sync,
832-
ExecutionMode::Enabled,
833-
probes,
833+
execution_mode.clone(),
834+
probes.clone(),
834835
60,
835836
5,
836837
);
@@ -845,6 +846,8 @@ mod tests {
845846
jwt_secret,
846847
builder_auth_rpc,
847848
jwt_secret,
849+
probes,
850+
execution_mode.clone(),
848851
));
849852

850853
let server = Server::builder()

0 commit comments

Comments
 (0)