Skip to content

Commit 0313cc2

Browse files
committed
Merge branch 'sigp-audit-fixes' into prevent-cross-module-sigs
2 parents d091a90 + b802fec commit 0313cc2

16 files changed

Lines changed: 238 additions & 81 deletions

File tree

crates/cli/src/docker_init.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use cb_common::{
1717
SIGNER_DIR_SECRETS_DEFAULT, SIGNER_DIR_SECRETS_ENV, SIGNER_ENDPOINT_ENV, SIGNER_KEYS_ENV,
1818
SIGNER_MODULE_NAME, SIGNER_PORT_DEFAULT, SIGNER_URL_ENV,
1919
},
20-
pbs::{BUILDER_API_PATH, GET_STATUS_PATH},
20+
pbs::{BUILDER_V1_API_PATH, GET_STATUS_PATH},
2121
signer::{ProxyStore, SignerLoader},
2222
types::ModuleId,
2323
utils::random_jwt_secret,
@@ -308,7 +308,7 @@ pub async fn handle_docker_init(config_path: PathBuf, output_dir: PathBuf) -> Re
308308
healthcheck: Some(Healthcheck {
309309
test: Some(HealthcheckTest::Single(format!(
310310
"curl -f http://localhost:{}{}{}",
311-
cb_config.pbs.pbs_config.port, BUILDER_API_PATH, GET_STATUS_PATH
311+
cb_config.pbs.pbs_config.port, BUILDER_V1_API_PATH, GET_STATUS_PATH
312312
))),
313313
interval: Some("30s".into()),
314314
timeout: Some("5s".into()),

crates/common/src/pbs/builder.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::fmt::{Display, Formatter, Result};
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
use crate::pbs::{BUILDER_V1_API_PATH, BUILDER_V2_API_PATH};
6+
7+
// Version of the builder API for various routes
8+
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
9+
#[serde(rename_all = "lowercase")]
10+
pub enum BuilderApiVersion {
11+
V1 = 1,
12+
V2,
13+
}
14+
impl BuilderApiVersion {
15+
pub const fn path(&self) -> &'static str {
16+
match self {
17+
BuilderApiVersion::V1 => BUILDER_V1_API_PATH,
18+
BuilderApiVersion::V2 => BUILDER_V2_API_PATH,
19+
}
20+
}
21+
}
22+
impl Display for BuilderApiVersion {
23+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
24+
let s = match self {
25+
BuilderApiVersion::V1 => "v1",
26+
BuilderApiVersion::V2 => "v2",
27+
};
28+
write!(f, "{}", s)
29+
}
30+
}

crates/common/src/pbs/constants.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::constants::COMMIT_BOOST_VERSION;
22

3-
pub const BUILDER_API_PATH: &str = "/eth/v1/builder";
3+
pub const BUILDER_V1_API_PATH: &str = "/eth/v1/builder";
4+
pub const BUILDER_V2_API_PATH: &str = "/eth/v2/builder";
45

56
pub const GET_HEADER_PATH: &str = "/header/{slot}/{parent_hash}/{pubkey}";
67
pub const GET_STATUS_PATH: &str = "/status";

crates/common/src/pbs/event.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use super::{
2020
};
2121
use crate::{
2222
config::{load_optional_env_var, BUILDER_URLS_ENV, HTTP_TIMEOUT_SECONDS_DEFAULT},
23-
pbs::BUILDER_EVENTS_PATH,
23+
pbs::{BuilderApiVersion, BUILDER_EVENTS_PATH},
2424
};
2525

2626
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -29,8 +29,9 @@ pub enum BuilderEvent {
2929
GetHeaderResponse(Box<Option<GetHeaderResponse>>),
3030
GetStatusEvent,
3131
GetStatusResponse,
32-
SubmitBlockRequest(Box<SignedBlindedBeaconBlock>),
33-
SubmitBlockResponse(Box<SubmitBlindedBlockResponse>),
32+
SubmitBlockRequest(Box<SignedBlindedBeaconBlock>, BuilderApiVersion),
33+
SubmitBlockResponseV1(Box<SubmitBlindedBlockResponse>),
34+
SubmitBlockResponseV2,
3435
MissedPayload {
3536
/// Hash for the block for which no payload was received
3637
block_hash: B256,

crates/common/src/pbs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
mod builder;
12
mod constants;
23
pub mod error;
34
mod event;
45
mod relay;
56
mod types;
67

8+
pub use builder::*;
79
pub use constants::*;
810
pub use event::*;
911
pub use relay::*;

crates/common/src/pbs/relay.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ use serde::{Deserialize, Serialize};
1010
use url::Url;
1111

1212
use super::{
13-
constants::{BUILDER_API_PATH, GET_STATUS_PATH, REGISTER_VALIDATOR_PATH, SUBMIT_BLOCK_PATH},
13+
constants::{GET_STATUS_PATH, REGISTER_VALIDATOR_PATH, SUBMIT_BLOCK_PATH},
1414
error::PbsError,
1515
HEADER_VERSION_KEY, HEADER_VERSION_VALUE,
1616
};
17-
use crate::{config::RelayConfig, DEFAULT_REQUEST_TIMEOUT};
17+
use crate::{config::RelayConfig, pbs::BuilderApiVersion, DEFAULT_REQUEST_TIMEOUT};
1818

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

102102
Ok(url)
103103
}
104-
pub fn builder_api_url(&self, path: &str) -> Result<Url, PbsError> {
105-
self.get_url(&format!("{BUILDER_API_PATH}{path}"))
104+
pub fn builder_api_url(
105+
&self,
106+
path: &str,
107+
api_version: BuilderApiVersion,
108+
) -> Result<Url, PbsError> {
109+
self.get_url(&format!("{}{path}", api_version.path()))
106110
}
107111

108112
pub fn get_header_url(
@@ -111,19 +115,22 @@ impl RelayClient {
111115
parent_hash: B256,
112116
validator_pubkey: BlsPublicKey,
113117
) -> Result<Url, PbsError> {
114-
self.builder_api_url(&format!("/header/{slot}/{parent_hash}/{validator_pubkey}"))
118+
self.builder_api_url(
119+
&format!("/header/{slot}/{parent_hash}/{validator_pubkey}"),
120+
BuilderApiVersion::V1,
121+
)
115122
}
116123

117124
pub fn get_status_url(&self) -> Result<Url, PbsError> {
118-
self.builder_api_url(GET_STATUS_PATH)
125+
self.builder_api_url(GET_STATUS_PATH, BuilderApiVersion::V1)
119126
}
120127

121128
pub fn register_validator_url(&self) -> Result<Url, PbsError> {
122-
self.builder_api_url(REGISTER_VALIDATOR_PATH)
129+
self.builder_api_url(REGISTER_VALIDATOR_PATH, BuilderApiVersion::V1)
123130
}
124131

125-
pub fn submit_block_url(&self) -> Result<Url, PbsError> {
126-
self.builder_api_url(SUBMIT_BLOCK_PATH)
132+
pub fn submit_block_url(&self, api_version: BuilderApiVersion) -> Result<Url, PbsError> {
133+
self.builder_api_url(SUBMIT_BLOCK_PATH, api_version)
127134
}
128135
}
129136

crates/pbs/src/api.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use alloy::rpc::types::beacon::relay::ValidatorRegistration;
22
use async_trait::async_trait;
33
use axum::{http::HeaderMap, Router};
44
use cb_common::pbs::{
5-
GetHeaderParams, GetHeaderResponse, SignedBlindedBeaconBlock, SubmitBlindedBlockResponse,
5+
BuilderApiVersion, GetHeaderParams, GetHeaderResponse, SignedBlindedBeaconBlock,
6+
SubmitBlindedBlockResponse,
67
};
78

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

34-
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock
35+
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock and
36+
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlockV2
3537
async fn submit_block(
3638
signed_blinded_block: SignedBlindedBeaconBlock,
3739
req_headers: HeaderMap,
3840
state: PbsState<S>,
39-
) -> eyre::Result<SubmitBlindedBlockResponse> {
40-
mev_boost::submit_block(signed_blinded_block, req_headers, state).await
41+
api_version: &BuilderApiVersion,
42+
) -> eyre::Result<Option<SubmitBlindedBlockResponse>> {
43+
mev_boost::submit_block(signed_blinded_block, req_headers, state, api_version).await
4144
}
4245

4346
/// https://ethereum.github.io/builder-specs/#/Builder/registerValidator

crates/pbs/src/mev_boost/submit_block.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use axum::http::{HeaderMap, HeaderValue};
44
use cb_common::{
55
pbs::{
66
error::{PbsError, ValidationError},
7-
BlindedBeaconBlock, BlindedBeaconBlockElectra, PayloadAndBlobsElectra, RelayClient,
8-
SignedBlindedBeaconBlock, SubmitBlindedBlockResponse, VersionedResponse,
7+
BlindedBeaconBlock, BlindedBeaconBlockElectra, BuilderApiVersion, PayloadAndBlobsElectra,
8+
RelayClient, SignedBlindedBeaconBlock, SubmitBlindedBlockResponse, VersionedResponse,
99
HEADER_START_TIME_UNIX_MS,
1010
},
1111
utils::{get_user_agent_with_version, read_chunked_body_with_max, utcnow_ms},
@@ -23,12 +23,15 @@ use crate::{
2323
state::{BuilderApiState, PbsState},
2424
};
2525

26-
/// Implements https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock
26+
/// Implements https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlock and
27+
/// https://ethereum.github.io/builder-specs/#/Builder/submitBlindedBlockV2. Use `api_version` to
28+
/// distinguish between the two.
2729
pub async fn submit_block<S: BuilderApiState>(
2830
signed_blinded_block: SignedBlindedBeaconBlock,
2931
req_headers: HeaderMap,
3032
state: PbsState<S>,
31-
) -> eyre::Result<SubmitBlindedBlockResponse> {
33+
api_version: &BuilderApiVersion,
34+
) -> eyre::Result<Option<SubmitBlindedBlockResponse>> {
3235
// prepare headers
3336
let mut send_headers = HeaderMap::new();
3437
send_headers.insert(HEADER_START_TIME_UNIX_MS, HeaderValue::from(utcnow_ms()));
@@ -42,6 +45,7 @@ pub async fn submit_block<S: BuilderApiState>(
4245
relay,
4346
send_headers.clone(),
4447
state.pbs_config().timeout_get_payload_ms,
48+
api_version,
4549
)));
4650
}
4751

@@ -59,8 +63,9 @@ async fn submit_block_with_timeout(
5963
relay: &RelayClient,
6064
headers: HeaderMap,
6165
timeout_ms: u64,
62-
) -> Result<SubmitBlindedBlockResponse, PbsError> {
63-
let url = relay.submit_block_url()?;
66+
api_version: &BuilderApiVersion,
67+
) -> Result<Option<SubmitBlindedBlockResponse>, PbsError> {
68+
let url = relay.submit_block_url(*api_version)?;
6469
let mut remaining_timeout_ms = timeout_ms;
6570
let mut retry = 0;
6671
let mut backoff = Duration::from_millis(250);
@@ -74,6 +79,7 @@ async fn submit_block_with_timeout(
7479
headers.clone(),
7580
remaining_timeout_ms,
7681
retry,
82+
api_version,
7783
)
7884
.await
7985
{
@@ -107,7 +113,8 @@ async fn send_submit_block(
107113
headers: HeaderMap,
108114
timeout_ms: u64,
109115
retry: u32,
110-
) -> Result<SubmitBlindedBlockResponse, PbsError> {
116+
api_version: &BuilderApiVersion,
117+
) -> Result<Option<SubmitBlindedBlockResponse>, PbsError> {
111118
let start_request = Instant::now();
112119
let res = match relay
113120
.client
@@ -151,6 +158,10 @@ async fn send_submit_block(
151158
warn!(relay_id = relay.id.as_ref(), retry, %err, "failed to get payload (this might be ok if other relays have it)");
152159
return Err(err);
153160
};
161+
if api_version != &BuilderApiVersion::V1 {
162+
// v2 response is going to be empty, so just break here
163+
return Ok(None);
164+
}
154165

155166
let block_response = match serde_json::from_slice::<SubmitBlindedBlockResponse>(&response_bytes)
156167
{
@@ -187,7 +198,7 @@ async fn send_submit_block(
187198
) => validate_unblinded_block_electra(signed_blinded_block, block_response),
188199
}?;
189200

190-
Ok(block_response)
201+
Ok(Some(block_response))
191202
}
192203

193204
fn validate_unblinded_block_electra(

crates/pbs/src/routes/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ use get_header::handle_get_header;
99
use register_validator::handle_register_validator;
1010
pub use router::create_app_router;
1111
use status::handle_get_status;
12-
use submit_block::handle_submit_block;
12+
use submit_block::handle_submit_block_v1;

crates/pbs/src/routes/router.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ use axum::{
77
};
88
use axum_extra::headers::{ContentType, HeaderMapExt, UserAgent};
99
use cb_common::pbs::{
10-
BUILDER_API_PATH, GET_HEADER_PATH, GET_STATUS_PATH, REGISTER_VALIDATOR_PATH, RELOAD_PATH,
11-
SUBMIT_BLOCK_PATH,
10+
BUILDER_V1_API_PATH, BUILDER_V2_API_PATH, GET_HEADER_PATH, GET_STATUS_PATH,
11+
REGISTER_VALIDATOR_PATH, RELOAD_PATH, SUBMIT_BLOCK_PATH,
1212
};
1313
use tracing::trace;
1414
use uuid::Uuid;
1515

1616
use super::{
17-
handle_get_header, handle_get_status, handle_register_validator, handle_submit_block,
17+
handle_get_header, handle_get_status, handle_register_validator, handle_submit_block_v1,
1818
reload::handle_reload,
1919
};
2020
use crate::{
2121
api::BuilderApi,
22+
routes::submit_block::handle_submit_block_v2,
2223
state::{BuilderApiState, PbsStateGuard},
2324
MAX_SIZE_REGISTER_VALIDATOR_REQUEST, MAX_SIZE_SUBMIT_BLOCK_RESPONSE,
2425
};
@@ -27,7 +28,7 @@ pub fn create_app_router<S: BuilderApiState, A: BuilderApi<S>>(state: PbsStateGu
2728
// DefaultBodyLimit is 2Mib by default, so we only increase it for a few routes
2829
// thay may need more
2930

30-
let builder_routes = Router::new()
31+
let v1_builder_routes = Router::new()
3132
.route(GET_HEADER_PATH, get(handle_get_header::<S, A>))
3233
.route(GET_STATUS_PATH, get(handle_get_status::<S, A>))
3334
.route(
@@ -37,11 +38,19 @@ pub fn create_app_router<S: BuilderApiState, A: BuilderApi<S>>(state: PbsStateGu
3738
)
3839
.route(
3940
SUBMIT_BLOCK_PATH,
40-
post(handle_submit_block::<S, A>)
41+
post(handle_submit_block_v1::<S, A>)
4142
.route_layer(DefaultBodyLimit::max(MAX_SIZE_SUBMIT_BLOCK_RESPONSE)),
4243
); // header is smaller than the response but err on the safe side
44+
let v2_builder_routes = Router::new().route(
45+
SUBMIT_BLOCK_PATH,
46+
post(handle_submit_block_v2::<S, A>)
47+
.route_layer(DefaultBodyLimit::max(MAX_SIZE_SUBMIT_BLOCK_RESPONSE)),
48+
);
49+
let v1_builder_router = Router::new().nest(BUILDER_V1_API_PATH, v1_builder_routes);
50+
let v2_builder_router = Router::new().nest(BUILDER_V2_API_PATH, v2_builder_routes);
4351
let reload_router = Router::new().route(RELOAD_PATH, post(handle_reload::<S, A>));
44-
let builder_api = Router::new().nest(BUILDER_API_PATH, builder_routes).merge(reload_router);
52+
let builder_api =
53+
Router::new().merge(v1_builder_router).merge(v2_builder_router).merge(reload_router);
4554

4655
let app = if let Some(extra_routes) = A::extra_routes() {
4756
builder_api.merge(extra_routes)

0 commit comments

Comments
 (0)