Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ ethereum_ssz_derive = "0.10"
eyre = "0.6.12"
futures = "0.3.30"
headers = "0.4.0"
headers-accept = "0.2.1"
indexmap = "2.2.6"
jsonwebtoken = { version = "9.3.1", default-features = false }
lazy_static = "1.5.0"
mediatype = "0.20.0"
lh_eth2 = { package = "eth2", git = "https://github.com/sigp/lighthouse", tag = "v8.1.3", features = ["events"] }
lh_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", tag = "v8.1.3" }
lh_bls = { package = "bls", git = "https://github.com/sigp/lighthouse", tag = "v8.1.3" }
Expand Down
2 changes: 2 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ ethereum_ssz.workspace = true
ethereum_ssz_derive.workspace = true
eyre.workspace = true
futures.workspace = true
headers-accept.workspace = true
jsonwebtoken.workspace = true
lazy_static.workspace = true
lh_bls.workspace = true
lh_eth2.workspace = true
lh_eth2_keystore.workspace = true
lh_types.workspace = true
mediatype.workspace = true
notify.workspace = true
pbkdf2.workspace = true
rand.workspace = true
Expand Down
18 changes: 14 additions & 4 deletions crates/common/src/config/mux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ use serde::{Deserialize, Serialize};
use tracing::{debug, info, warn};
use url::Url;

use super::{MUX_PATH_ENV, PbsConfig, RelayConfig, load_optional_env_var};
use super::{MUX_PATH_ENV, MUXER_HTTP_MAX_LENGTH, PbsConfig, RelayConfig, load_optional_env_var};
use crate::{
config::{remove_duplicate_keys, safe_read_http_response},
config::remove_duplicate_keys,
interop::{lido::utils::*, ssv::utils::*},
pbs::RelayClient,
types::{BlsPublicKey, Chain},
utils::default_bool,
wire::read_chunked_body_with_max,
};

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

impl MuxConfig {
/// Returns the env, actual path, and internal path to use for the file
/// loader. In File mode, validates the mux file prior to returning.
/// loader. In File mode, validates the mux file prior to returning.
pub fn loader_env(&self) -> eyre::Result<Option<(String, String, String)>> {
let Some(loader) = self.loader.as_ref() else {
return Ok(None);
Expand Down Expand Up @@ -237,7 +238,16 @@ impl MuxKeysLoader {
}
let client = reqwest::ClientBuilder::new().timeout(http_timeout).build()?;
let response = client.get(url).send().await?;
let pubkey_bytes = safe_read_http_response(response).await?;
let status = response.status();
let pubkey_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
.await
.wrap_err("Failed to read response body")?;
if !status.is_success() {
bail!(
"Request failed with status: {status}, body: {}",
String::from_utf8_lossy(&pubkey_bytes)
);
}
serde_json::from_slice(&pubkey_bytes)
.wrap_err("failed to fetch mux keys from HTTP endpoint")
}
Expand Down
29 changes: 1 addition & 28 deletions crates/common/src/config/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ use eyre::{Context, Result, bail};
use serde::de::DeserializeOwned;

use crate::{
config::{ADMIN_JWT_ENV, JWTS_ENV, MUXER_HTTP_MAX_LENGTH},
config::{ADMIN_JWT_ENV, JWTS_ENV},
types::{BlsPublicKey, ModuleId},
utils::read_chunked_body_with_max,
};

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

/// Reads an HTTP response safely, erroring out if it failed or if the body is
/// too large.
pub async fn safe_read_http_response(response: reqwest::Response) -> Result<Vec<u8>> {
// Read the response to a buffer in chunks
let status_code = response.status();
match read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH).await {
Ok(response_bytes) => {
if status_code.is_success() {
return Ok(response_bytes);
}
bail!(
"Request failed with status: {status_code}, body: {}",
String::from_utf8_lossy(&response_bytes)
)
}
Err(e) => {
if status_code.is_success() {
return Err(e).wrap_err("Failed to read response body");
}
Err(e).wrap_err(format!(
"Request failed with status {status_code}, but decoding the response body failed"
))
}
}
}

/// Removes duplicate entries from a vector of BlsPublicKey
pub fn remove_duplicate_keys(keys: Vec<BlsPublicKey>) -> Vec<BlsPublicKey> {
let mut unique_keys = Vec::new();
Expand Down
27 changes: 23 additions & 4 deletions crates/common/src/interop/ssv/utils.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::time::Duration;

use alloy::primitives::U256;
use eyre::Context;
use eyre::{Context, bail};
use serde_json::json;
use url::Url;

use crate::{
config::safe_read_http_response,
config::MUXER_HTTP_MAX_LENGTH,
interop::ssv::types::{SSVNodeResponse, SSVPublicResponse},
wire::read_chunked_body_with_max,
};

pub async fn request_ssv_pubkeys_from_ssv_node(
Expand All @@ -28,7 +29,16 @@ pub async fn request_ssv_pubkeys_from_ssv_node(
})?;

// Parse the response as JSON
let body_bytes = safe_read_http_response(response).await?;
let status = response.status();
let body_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
.await
.wrap_err("Failed to read response body")?;
if !status.is_success() {
bail!(
"Request failed with status: {status}, body: {}",
String::from_utf8_lossy(&body_bytes)
);
}
serde_json::from_slice::<SSVNodeResponse>(&body_bytes).wrap_err("failed to parse SSV response")
}

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

// Parse the response as JSON
let body_bytes = safe_read_http_response(response).await?;
let status = response.status();
let body_bytes = read_chunked_body_with_max(response, MUXER_HTTP_MAX_LENGTH)
.await
.wrap_err("Failed to read response body")?;
if !status.is_success() {
bail!(
"Request failed with status: {status}, body: {}",
String::from_utf8_lossy(&body_bytes)
);
}
serde_json::from_slice::<SSVPublicResponse>(&body_bytes)
.wrap_err("failed to parse SSV response")
}
2 changes: 2 additions & 0 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ pub mod interop;
pub mod pbs;
pub mod signature;
pub mod signer;
pub mod ssz;
pub mod types;
pub mod utils;
pub mod wire;

pub const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(12);
15 changes: 14 additions & 1 deletion crates/common/src/pbs/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use alloy::primitives::{B256, U256};
use lh_types::ForkName;
use thiserror::Error;

use crate::{types::BlsPublicKeyBytes, utils::ResponseReadError};
use crate::{types::BlsPublicKeyBytes, wire::ResponseReadError};

#[derive(Debug, Error)]
pub enum PbsError {
Expand All @@ -28,6 +29,9 @@ pub enum PbsError {

#[error("tokio join error: {0}")]
TokioJoinError(#[from] tokio::task::JoinError),

#[error("SSZ error: {0}")]
SszError(#[from] SszValueError),
}

impl PbsError {
Expand Down Expand Up @@ -107,3 +111,12 @@ pub enum ValidationError {
#[error("unsupported fork")]
UnsupportedFork,
}

#[derive(Debug, Error, PartialEq, Eq)]
pub enum SszValueError {
#[error("invalid payload length: required {required} but payload was {actual}")]
InvalidPayloadLength { required: usize, actual: usize },

#[error("unsupported fork: {name}")]
UnsupportedFork { name: ForkName },
}
1 change: 1 addition & 0 deletions crates/common/src/pbs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ mod types;

pub use builder::*;
pub use constants::*;
pub use lh_types::ForkVersionDecode;
pub use relay::*;
pub use types::*;
10 changes: 9 additions & 1 deletion crates/common/src/pbs/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use alloy::primitives::{B256, U256, b256};
use lh_eth2::ForkVersionedResponse;
pub use lh_eth2::ForkVersionedResponse;
pub use lh_types::ForkName;
use lh_types::{BlindedPayload, ExecPayload, MainnetEthSpec};
use serde::{Deserialize, Serialize};
Expand All @@ -26,6 +26,10 @@ pub type PayloadAndBlobs = lh_eth2::types::ExecutionPayloadAndBlobs<MainnetEthSp
pub type SubmitBlindedBlockResponse = ForkVersionedResponse<PayloadAndBlobs>;

pub type ExecutionPayloadHeader = lh_types::ExecutionPayloadHeader<MainnetEthSpec>;
pub type ExecutionPayloadHeaderBellatrix =
lh_types::ExecutionPayloadHeaderBellatrix<MainnetEthSpec>;
pub type ExecutionPayloadHeaderCapella = lh_types::ExecutionPayloadHeaderCapella<MainnetEthSpec>;
pub type ExecutionPayloadHeaderDeneb = lh_types::ExecutionPayloadHeaderDeneb<MainnetEthSpec>;
pub type ExecutionPayloadHeaderElectra = lh_types::ExecutionPayloadHeaderElectra<MainnetEthSpec>;
pub type ExecutionPayloadHeaderFulu = lh_types::ExecutionPayloadHeaderFulu<MainnetEthSpec>;
pub type ExecutionPayloadHeaderRef<'a> = lh_types::ExecutionPayloadHeaderRef<'a, MainnetEthSpec>;
Expand All @@ -34,7 +38,11 @@ pub type ExecutionPayloadElectra = lh_types::ExecutionPayloadElectra<MainnetEthS
pub type ExecutionPayloadFulu = lh_types::ExecutionPayloadFulu<MainnetEthSpec>;
pub type SignedBuilderBid = lh_types::SignedBuilderBid<MainnetEthSpec>;
pub type BuilderBid = lh_types::BuilderBid<MainnetEthSpec>;
pub type BuilderBidBellatrix = lh_types::BuilderBidBellatrix<MainnetEthSpec>;
pub type BuilderBidCapella = lh_types::BuilderBidCapella<MainnetEthSpec>;
pub type BuilderBidDeneb = lh_types::BuilderBidDeneb<MainnetEthSpec>;
Comment thread
JasonVranek marked this conversation as resolved.
pub type BuilderBidElectra = lh_types::BuilderBidElectra<MainnetEthSpec>;
pub type BuilderBidFulu = lh_types::BuilderBidFulu<MainnetEthSpec>;

/// Response object of GET
/// `/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}`
Expand Down
Loading
Loading