Skip to content
Merged
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
4 changes: 2 additions & 2 deletions crates/cli/src/docker_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use cb_common::{
SIGNER_DIR_SECRETS_ENV, SIGNER_ENDPOINT_ENV, SIGNER_KEYS_ENV, SIGNER_MODULE_NAME,
SIGNER_PORT_DEFAULT, SIGNER_URL_ENV,
},
pbs::{BUILDER_API_PATH, GET_STATUS_PATH},
pbs::{BUILDER_V1_API_PATH, GET_STATUS_PATH},
signer::{ProxyStore, SignerLoader},
types::ModuleId,
utils::random_jwt_secret,
Expand Down Expand Up @@ -308,7 +308,7 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
healthcheck: Some(Healthcheck {
test: Some(HealthcheckTest::Single(format!(
"curl -f http://localhost:{}{}{}",
cb_config.pbs.pbs_config.port, BUILDER_API_PATH, GET_STATUS_PATH
cb_config.pbs.pbs_config.port, BUILDER_V1_API_PATH, GET_STATUS_PATH
))),
interval: Some("30s".into()),
timeout: Some("5s".into()),
Expand Down
30 changes: 30 additions & 0 deletions crates/common/src/pbs/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::fmt::{Display, Formatter, Result};

use serde::{Deserialize, Serialize};

use crate::pbs::{BUILDER_V1_API_PATH, BUILDER_V2_API_PATH};

// Version of the builder API for various routes
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum BuilderApiVersion {
V1 = 1,
V2,
}
impl BuilderApiVersion {
pub const fn path(&self) -> &'static str {
match self {
BuilderApiVersion::V1 => BUILDER_V1_API_PATH,
BuilderApiVersion::V2 => BUILDER_V2_API_PATH,
}
}
}
impl Display for BuilderApiVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let s = match self {
BuilderApiVersion::V1 => "v1",
BuilderApiVersion::V2 => "v2",
};
write!(f, "{}", s)
}
}
3 changes: 2 additions & 1 deletion crates/common/src/pbs/constants.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::constants::COMMIT_BOOST_VERSION;

pub const BUILDER_API_PATH: &str = "/eth/v1/builder";
pub const BUILDER_V1_API_PATH: &str = "/eth/v1/builder";
pub const BUILDER_V2_API_PATH: &str = "/eth/v2/builder";

pub const GET_HEADER_PATH: &str = "/header/{slot}/{parent_hash}/{pubkey}";
pub const GET_STATUS_PATH: &str = "/status";
Expand Down
7 changes: 4 additions & 3 deletions crates/common/src/pbs/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use super::{
};
use crate::{
config::{load_optional_env_var, BUILDER_URLS_ENV, HTTP_TIMEOUT_SECONDS_DEFAULT},
pbs::BUILDER_EVENTS_PATH,
pbs::{BuilderApiVersion, BUILDER_EVENTS_PATH},
};

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -29,8 +29,9 @@ pub enum BuilderEvent {
GetHeaderResponse(Box<Option<GetHeaderResponse>>),
GetStatusEvent,
GetStatusResponse,
SubmitBlockRequest(Box<SignedBlindedBeaconBlock>),
SubmitBlockResponse(Box<SubmitBlindedBlockResponse>),
SubmitBlockRequest(Box<SignedBlindedBeaconBlock>, BuilderApiVersion),
SubmitBlockResponseV1(Box<SubmitBlindedBlockResponse>),
SubmitBlockResponseV2,
MissedPayload {
/// Hash for the block for which no payload was received
block_hash: B256,
Expand Down
2 changes: 2 additions & 0 deletions crates/common/src/pbs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod builder;
mod constants;
pub mod error;
mod event;
mod relay;
mod types;

pub use builder::*;
pub use constants::*;
pub use event::*;
pub use relay::*;
Expand Down
25 changes: 16 additions & 9 deletions crates/common/src/pbs/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ use serde::{Deserialize, Serialize};
use url::Url;

use super::{
constants::{BUILDER_API_PATH, GET_STATUS_PATH, REGISTER_VALIDATOR_PATH, SUBMIT_BLOCK_PATH},
constants::{GET_STATUS_PATH, REGISTER_VALIDATOR_PATH, SUBMIT_BLOCK_PATH},
error::PbsError,
HEADER_VERSION_KEY, HEADER_VERSION_VALUE,
};
use crate::{config::RelayConfig, DEFAULT_REQUEST_TIMEOUT};
use crate::{config::RelayConfig, pbs::BuilderApiVersion, DEFAULT_REQUEST_TIMEOUT};

/// A parsed entry of the relay url in the format: scheme://pubkey@host
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -101,8 +101,12 @@ impl RelayClient {

Ok(url)
}
pub fn builder_api_url(&self, path: &str) -> Result<Url, PbsError> {
self.get_url(&format!("{BUILDER_API_PATH}{path}"))
pub fn builder_api_url(
&self,
path: &str,
api_version: BuilderApiVersion,
) -> Result<Url, PbsError> {
self.get_url(&format!("{}{path}", api_version.path()))
}

pub fn get_header_url(
Expand All @@ -111,19 +115,22 @@ impl RelayClient {
parent_hash: B256,
validator_pubkey: BlsPublicKey,
) -> Result<Url, PbsError> {
self.builder_api_url(&format!("/header/{slot}/{parent_hash}/{validator_pubkey}"))
self.builder_api_url(
&format!("/header/{slot}/{parent_hash}/{validator_pubkey}"),
BuilderApiVersion::V1,
)
}

pub fn get_status_url(&self) -> Result<Url, PbsError> {
self.builder_api_url(GET_STATUS_PATH)
self.builder_api_url(GET_STATUS_PATH, BuilderApiVersion::V1)
}

pub fn register_validator_url(&self) -> Result<Url, PbsError> {
self.builder_api_url(REGISTER_VALIDATOR_PATH)
self.builder_api_url(REGISTER_VALIDATOR_PATH, BuilderApiVersion::V1)
}

pub fn submit_block_url(&self) -> Result<Url, PbsError> {
self.builder_api_url(SUBMIT_BLOCK_PATH)
pub fn submit_block_url(&self, api_version: BuilderApiVersion) -> Result<Url, PbsError> {
self.builder_api_url(SUBMIT_BLOCK_PATH, api_version)
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/common/src/pbs/types/beacon_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ mod tests {
// this is from mev-boost test data
fn test_signed_blinded_block_fb_electra() {
let data = include_str!("testdata/signed-blinded-beacon-block-electra.json");
let block = test_encode_decode::<SignedBlindedBeaconBlock>(&data);
let block = test_encode_decode::<SignedBlindedBeaconBlock>(data);
assert!(matches!(block.message, BlindedBeaconBlock::Electra(_)));
}

Expand Down Expand Up @@ -166,7 +166,7 @@ mod tests {
// this is dummy data generated with https://github.com/attestantio/go-eth2-client
fn test_signed_blinded_block_ssz() {
let data_json = include_str!("testdata/signed-blinded-beacon-block-electra-2.json");
let block_json = test_encode_decode::<SignedBlindedBeaconBlock>(&data_json);
let block_json = test_encode_decode::<SignedBlindedBeaconBlock>(data_json);
assert!(matches!(block_json.message, BlindedBeaconBlock::Electra(_)));

let data_ssz = include_bytes!("testdata/signed-blinded-beacon-block-electra-2.ssz");
Expand All @@ -181,7 +181,7 @@ mod tests {
// this is dummy data generated with https://github.com/attestantio/go-builder-client
fn test_execution_payload_block_ssz() {
let data_json = include_str!("testdata/execution-payload-electra.json");
let block_json = test_encode_decode::<PayloadAndBlobsElectra>(&data_json);
let block_json = test_encode_decode::<PayloadAndBlobsElectra>(data_json);

let data_ssz = include_bytes!("testdata/execution-payload-electra.ssz");
let data_ssz = alloy::primitives::hex::decode(data_ssz).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/pbs/types/execution_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ mod tests {
"excess_blob_gas": "95158272"
}"#;

let parsed = test_encode_decode::<ExecutionPayloadHeader<ElectraSpec>>(&data);
let parsed = test_encode_decode::<ExecutionPayloadHeader<ElectraSpec>>(data);

assert_eq!(
parsed.parent_hash,
Expand Down
4 changes: 2 additions & 2 deletions crates/common/src/pbs/types/get_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ mod tests {
}
}"#;

let parsed = test_encode_decode::<GetHeaderResponse>(&data);
let parsed = test_encode_decode::<GetHeaderResponse>(data);
let VersionedResponse::Electra(parsed) = parsed;

assert_eq!(parsed.message.value, U256::from(1));
Expand All @@ -187,7 +187,7 @@ mod tests {
let data_json = include_str!("testdata/get-header-response.json");
let block_json = test_encode_decode::<
SignedExecutionPayloadHeader<ExecutionPayloadHeaderMessageElectra>,
>(&data_json);
>(data_json);

let data_ssz = include_bytes!("testdata/get-header-response.ssz");
let data_ssz = alloy::primitives::hex::decode(data_ssz).unwrap();
Expand Down
6 changes: 3 additions & 3 deletions crates/common/src/signer/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,12 +542,12 @@ mod test {
.join(consensus_signer.pubkey().to_string())
.join("TEST_MODULE")
.join("bls")
.join(format!("{}.json", proxy_signer.pubkey().to_string()));
.join(format!("{}.json", proxy_signer.pubkey()));
let sig_path = keys_path
.join(consensus_signer.pubkey().to_string())
.join("TEST_MODULE")
.join("bls")
.join(format!("{}.sig", proxy_signer.pubkey().to_string()));
.join(format!("{}.sig", proxy_signer.pubkey()));
let pass_path = secrets_path
.join(consensus_signer.pubkey().to_string())
.join("TEST_MODULE")
Expand Down Expand Up @@ -674,7 +674,7 @@ mod test {
.join(consensus_signer.pubkey().to_string())
.join("TEST_MODULE")
.join("bls")
.join(format!("{}.sig", proxy_signer.pubkey().to_string()))
.join(format!("{}.sig", proxy_signer.pubkey()))
)
.unwrap()
)
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ mod test {
let jwt = create_jwt(&ModuleId("DA_COMMIT".to_string()), "secret").unwrap();
let module_id = decode_jwt(jwt.clone()).unwrap();
assert_eq!(module_id, ModuleId("DA_COMMIT".to_string()));
let response = validate_jwt(jwt, "secret".as_ref());
let response = validate_jwt(jwt, "secret");
assert!(response.is_ok());

// Check expired JWT
Expand Down
11 changes: 7 additions & 4 deletions crates/pbs/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use alloy::rpc::types::beacon::relay::ValidatorRegistration;
use async_trait::async_trait;
use axum::{http::HeaderMap, Router};
use cb_common::pbs::{
GetHeaderParams, GetHeaderResponse, SignedBlindedBeaconBlock, SubmitBlindedBlockResponse,
BuilderApiVersion, GetHeaderParams, GetHeaderResponse, SignedBlindedBeaconBlock,
SubmitBlindedBlockResponse,
};

use crate::{
Expand Down Expand Up @@ -31,13 +32,15 @@ pub trait BuilderApi<S: BuilderApiState>: 'static {
mev_boost::get_status(req_headers, state).await
}

/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock and
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlockV2
async fn submit_block(
signed_blinded_block: SignedBlindedBeaconBlock,
req_headers: HeaderMap,
state: PbsState<S>,
) -> eyre::Result<SubmitBlindedBlockResponse> {
mev_boost::submit_block(signed_blinded_block, req_headers, state).await
api_version: &BuilderApiVersion,
) -> eyre::Result<Option<SubmitBlindedBlockResponse>> {
mev_boost::submit_block(signed_blinded_block, req_headers, state, api_version).await
}

/// https://ethereum.github.io/builder-specs/#/Builder/registerValidator
Expand Down
27 changes: 19 additions & 8 deletions crates/pbs/src/mev_boost/submit_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use axum::http::{HeaderMap, HeaderValue};
use cb_common::{
pbs::{
error::{PbsError, ValidationError},
BlindedBeaconBlock, BlindedBeaconBlockElectra, PayloadAndBlobsElectra, RelayClient,
SignedBlindedBeaconBlock, SubmitBlindedBlockResponse, VersionedResponse,
BlindedBeaconBlock, BlindedBeaconBlockElectra, BuilderApiVersion, PayloadAndBlobsElectra,
RelayClient, SignedBlindedBeaconBlock, SubmitBlindedBlockResponse, VersionedResponse,
HEADER_START_TIME_UNIX_MS,
},
utils::{get_user_agent_with_version, read_chunked_body_with_max, utcnow_ms},
Expand All @@ -23,12 +23,15 @@ use crate::{
state::{BuilderApiState, PbsState},
};

/// Implements https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock
/// Implements https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock and
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlockV2. Use `api_version` to
/// distinguish between the two.
pub async fn submit_block<S: BuilderApiState>(
signed_blinded_block: SignedBlindedBeaconBlock,
req_headers: HeaderMap,
state: PbsState<S>,
) -> eyre::Result<SubmitBlindedBlockResponse> {
api_version: &BuilderApiVersion,
) -> eyre::Result<Option<SubmitBlindedBlockResponse>> {
// prepare headers
let mut send_headers = HeaderMap::new();
send_headers.insert(HEADER_START_TIME_UNIX_MS, HeaderValue::from(utcnow_ms()));
Expand All @@ -42,6 +45,7 @@ pub async fn submit_block<S: BuilderApiState>(
relay,
send_headers.clone(),
state.pbs_config().timeout_get_payload_ms,
api_version,
)));
}

Expand All @@ -59,8 +63,9 @@ async fn submit_block_with_timeout(
relay: &RelayClient,
headers: HeaderMap,
timeout_ms: u64,
) -> Result<SubmitBlindedBlockResponse, PbsError> {
let url = relay.submit_block_url()?;
api_version: &BuilderApiVersion,
) -> Result<Option<SubmitBlindedBlockResponse>, PbsError> {
let url = relay.submit_block_url(*api_version)?;
let mut remaining_timeout_ms = timeout_ms;
let mut retry = 0;
let mut backoff = Duration::from_millis(250);
Expand All @@ -74,6 +79,7 @@ async fn submit_block_with_timeout(
headers.clone(),
remaining_timeout_ms,
retry,
api_version,
)
.await
{
Expand Down Expand Up @@ -107,7 +113,8 @@ async fn send_submit_block(
headers: HeaderMap,
timeout_ms: u64,
retry: u32,
) -> Result<SubmitBlindedBlockResponse, PbsError> {
api_version: &BuilderApiVersion,
) -> Result<Option<SubmitBlindedBlockResponse>, PbsError> {
let start_request = Instant::now();
let res = match relay
.client
Expand Down Expand Up @@ -151,6 +158,10 @@ async fn send_submit_block(
warn!(relay_id = relay.id.as_ref(), retry, %err, "failed to get payload (this might be ok if other relays have it)");
return Err(err);
};
if api_version != &BuilderApiVersion::V1 {
// v2 response is going to be empty, so just break here
return Ok(None);
}

let block_response = match serde_json::from_slice::<SubmitBlindedBlockResponse>(&response_bytes)
{
Expand Down Expand Up @@ -187,7 +198,7 @@ async fn send_submit_block(
) => validate_unblinded_block_electra(signed_blinded_block, block_response),
}?;

Ok(block_response)
Ok(Some(block_response))
}

fn validate_unblinded_block_electra(
Expand Down
2 changes: 1 addition & 1 deletion crates/pbs/src/routes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ use get_header::handle_get_header;
use register_validator::handle_register_validator;
pub use router::create_app_router;
use status::handle_get_status;
use submit_block::handle_submit_block;
use submit_block::handle_submit_block_v1;
Loading