Skip to content

Commit 90ca2ea

Browse files
committed
address review comments, inline safe_read_http_response (name implied
general but mux-specific)
1 parent 0b82ae1 commit 90ca2ea

6 files changed

Lines changed: 43 additions & 56 deletions

File tree

crates/common/src/config/mux.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ use serde::{Deserialize, Serialize};
1818
use tracing::{debug, info, warn};
1919
use url::Url;
2020

21-
use super::{MUX_PATH_ENV, PbsConfig, RelayConfig, load_optional_env_var};
21+
use super::{MUX_PATH_ENV, MUXER_HTTP_MAX_LENGTH, PbsConfig, RelayConfig, load_optional_env_var};
2222
use crate::{
23-
config::{remove_duplicate_keys, safe_read_http_response},
23+
config::remove_duplicate_keys,
2424
interop::{lido::utils::*, ssv::utils::*},
2525
pbs::RelayClient,
2626
types::{BlsPublicKey, Chain},
2727
utils::default_bool,
28+
wire::read_chunked_body_with_max,
2829
};
2930

3031
#[derive(Debug, Clone, Deserialize, Serialize)]
@@ -156,7 +157,7 @@ pub struct MuxConfig {
156157

157158
impl MuxConfig {
158159
/// Returns the env, actual path, and internal path to use for the file
159-
/// loader. In File mode, validates the mux file prior to returning.
160+
/// loader. In File mode, validates the mux file prior to returning.
160161
pub fn loader_env(&self) -> eyre::Result<Option<(String, String, String)>> {
161162
let Some(loader) = self.loader.as_ref() else {
162163
return Ok(None);
@@ -237,7 +238,16 @@ impl MuxKeysLoader {
237238
}
238239
let client = reqwest::ClientBuilder::new().timeout(http_timeout).build()?;
239240
let response = client.get(url).send().await?;
240-
let pubkey_bytes = safe_read_http_response(response).await?;
241+
let status = response.status();
242+
let pubkey_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
243+
.await
244+
.wrap_err("Failed to read response body")?;
245+
if !status.is_success() {
246+
bail!(
247+
"Request failed with status: {status}, body: {}",
248+
String::from_utf8_lossy(&pubkey_bytes)
249+
);
250+
}
241251
serde_json::from_slice(&pubkey_bytes)
242252
.wrap_err("failed to fetch mux keys from HTTP endpoint")
243253
}

crates/common/src/config/utils.rs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ use eyre::{Context, Result, bail};
77
use serde::de::DeserializeOwned;
88

99
use crate::{
10-
config::{ADMIN_JWT_ENV, JWTS_ENV, MUXER_HTTP_MAX_LENGTH},
10+
config::{ADMIN_JWT_ENV, JWTS_ENV},
1111
types::{BlsPublicKey, ModuleId},
12-
wire::read_chunked_body_with_max,
1312
};
1413

1514
pub fn load_env_var(env: &str) -> Result<String> {
@@ -42,32 +41,6 @@ pub fn load_jwt_secrets() -> Result<(String, HashMap<ModuleId, String>)> {
4241
decode_string_to_map(&jwt_secrets).map(|secrets| (admin_jwt, secrets))
4342
}
4443

45-
/// Reads an HTTP response safely, erroring out if it failed or if the body is
46-
/// too large.
47-
pub async fn safe_read_http_response(response: reqwest::Response) -> Result<Vec<u8>> {
48-
// Read the response to a buffer in chunks
49-
let status_code = response.status();
50-
match read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH).await {
51-
Ok(response_bytes) => {
52-
if status_code.is_success() {
53-
return Ok(response_bytes);
54-
}
55-
bail!(
56-
"Request failed with status: {status_code}, body: {}",
57-
String::from_utf8_lossy(&response_bytes)
58-
)
59-
}
60-
Err(e) => {
61-
if status_code.is_success() {
62-
return Err(e).wrap_err("Failed to read response body");
63-
}
64-
Err(e).wrap_err(format!(
65-
"Request failed with status {status_code}, but decoding the response body failed"
66-
))
67-
}
68-
}
69-
}
70-
7144
/// Removes duplicate entries from a vector of BlsPublicKey
7245
pub fn remove_duplicate_keys(keys: Vec<BlsPublicKey>) -> Vec<BlsPublicKey> {
7346
let mut unique_keys = Vec::new();

crates/common/src/interop/ssv/utils.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use std::time::Duration;
22

33
use alloy::primitives::U256;
4-
use eyre::Context;
4+
use eyre::{Context, bail};
55
use serde_json::json;
66
use url::Url;
77

88
use crate::{
9-
config::safe_read_http_response,
9+
config::MUXER_HTTP_MAX_LENGTH,
1010
interop::ssv::types::{SSVNodeResponse, SSVPublicResponse},
11+
wire::read_chunked_body_with_max,
1112
};
1213

1314
pub async fn request_ssv_pubkeys_from_ssv_node(
@@ -28,7 +29,16 @@ pub async fn request_ssv_pubkeys_from_ssv_node(
2829
})?;
2930

3031
// Parse the response as JSON
31-
let body_bytes = safe_read_http_response(response).await?;
32+
let status = response.status();
33+
let body_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
34+
.await
35+
.wrap_err("Failed to read response body")?;
36+
if !status.is_success() {
37+
bail!(
38+
"Request failed with status: {status}, body: {}",
39+
String::from_utf8_lossy(&body_bytes)
40+
);
41+
}
3242
serde_json::from_slice::<SSVNodeResponse>(&body_bytes).wrap_err("failed to parse SSV response")
3343
}
3444

@@ -46,7 +56,16 @@ pub async fn request_ssv_pubkeys_from_public_api(
4656
})?;
4757

4858
// Parse the response as JSON
49-
let body_bytes = safe_read_http_response(response).await?;
59+
let status = response.status();
60+
let body_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
61+
.await
62+
.wrap_err("Failed to read response body")?;
63+
if !status.is_success() {
64+
bail!(
65+
"Request failed with status: {status}, body: {}",
66+
String::from_utf8_lossy(&body_bytes)
67+
);
68+
}
5069
serde_json::from_slice::<SSVPublicResponse>(&body_bytes)
5170
.wrap_err("failed to parse SSV response")
5271
}

crates/common/src/ssz.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,13 @@
11
use alloy::primitives::U256;
22
use lh_bls::Signature;
33
use lh_types::ForkName;
4-
use ssz::{BYTES_PER_LENGTH_OFFSET, Decode, Encode};
4+
use ssz::BYTES_PER_LENGTH_OFFSET;
55

66
use crate::pbs::{
77
BuilderBidFulu, ExecutionPayloadHeaderFulu, ExecutionRequests, KzgCommitments,
88
error::SszValueError,
99
};
1010

11-
/// Test that SSZ encoding and decoding round-trips, returning the decoded
12-
/// struct.
13-
pub fn test_encode_decode_ssz<T: Encode + Decode>(d: &[u8]) -> T {
14-
let decoded = T::from_ssz_bytes(d).expect("deserialize");
15-
let encoded = T::as_ssz_bytes(&decoded);
16-
assert_eq!(encoded, d);
17-
decoded
18-
}
19-
2011
// Get the offset of the message in a SignedBuilderBid SSZ structure
2112
fn get_ssz_value_offset_for_fork(fork: ForkName) -> Result<usize, SszValueError> {
2213
match fork {

crates/common/src/wire.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ pub const CONSENSUS_VERSION_HEADER: &str = "Eth-Consensus-Version";
2323

2424
#[derive(Debug, Error)]
2525
pub enum ResponseReadError {
26-
#[error(
27-
"response size exceeds max size; max: {max}, content_length: {content_length}, raw: {raw}"
28-
)]
29-
PayloadTooLarge { max: usize, content_length: usize, raw: String },
26+
#[error("response size exceeds max size; max: {max}, content_length: {content_length}")]
27+
PayloadTooLarge { max: usize, content_length: usize },
3028

3129
#[error("error reading response stream: {0}")]
3230
ReqwestError(#[from] reqwest::Error),
@@ -74,7 +72,6 @@ pub async fn read_chunked_body_with_max(
7472
return Err(ResponseReadError::PayloadTooLarge {
7573
max: max_size,
7674
content_length: length as usize,
77-
raw: String::new(), // raw content is not available here
7875
});
7976
}
8077

@@ -89,7 +86,6 @@ pub async fn read_chunked_body_with_max(
8986
return Err(ResponseReadError::PayloadTooLarge {
9087
max: max_size,
9188
content_length: content_length.unwrap_or(0) as usize,
92-
raw: String::from_utf8_lossy(&response_bytes).into_owned(),
9389
});
9490
}
9591

tests/tests/pbs_mux.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,9 @@ async fn test_ssv_network_fetch_big_data() -> Result<()> {
8686
panic!("Expected an error due to big content length, but got a successful response")
8787
}
8888
Err(e) => match e.downcast_ref::<ResponseReadError>() {
89-
Some(ResponseReadError::PayloadTooLarge { max, content_length, raw }) => {
89+
Some(ResponseReadError::PayloadTooLarge { max, content_length }) => {
9090
assert_eq!(*max, MUXER_HTTP_MAX_LENGTH);
9191
assert!(*content_length > MUXER_HTTP_MAX_LENGTH);
92-
assert!(raw.is_empty());
9392
}
9493
_ => panic!("Expected PayloadTooLarge error, got: {}", e),
9594
},
@@ -147,10 +146,9 @@ async fn test_ssv_network_fetch_big_data_without_content_length() -> Result<()>
147146
panic!("Expected an error due to excessive data, but got a successful response")
148147
}
149148
Err(e) => match e.downcast_ref::<ResponseReadError>() {
150-
Some(ResponseReadError::PayloadTooLarge { max, content_length, raw }) => {
149+
Some(ResponseReadError::PayloadTooLarge { max, content_length }) => {
151150
assert_eq!(*max, MUXER_HTTP_MAX_LENGTH);
152151
assert_eq!(*content_length, 0);
153-
assert!(!raw.is_empty());
154152
}
155153
_ => panic!("Expected PayloadTooLarge error, got: {}", e),
156154
},

0 commit comments

Comments
 (0)