Skip to content

Commit 83ca8f8

Browse files
committed
Added more multitype tests to submit_block, not done yet though
1 parent aaa0967 commit 83ca8f8

File tree

4 files changed

+148
-26
lines changed

4 files changed

+148
-26
lines changed

crates/common/src/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ pub fn get_accept_types(req_headers: &HeaderMap) -> eyre::Result<HashSet<Encodin
458458
return Err(eyre::eyre!("unsupported accept type"));
459459
}
460460

461-
// No accept header so just return JSON
462-
accepted_types.insert(EncodingType::Json);
461+
// No accept header so just return the same type as the content type
462+
accepted_types.insert(get_content_type(req_headers));
463463
}
464464
Ok(accepted_types)
465465
}

crates/pbs/src/mev_boost/submit_block.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ use cb_common::{
1414
error::{PbsError, ValidationError},
1515
},
1616
utils::{
17-
EncodingType, get_accept_types, get_user_agent_with_version, read_chunked_body_with_max,
18-
utcnow_ms,
17+
EncodingType, get_accept_types, get_content_type, get_user_agent_with_version,
18+
read_chunked_body_with_max, utcnow_ms,
1919
},
2020
};
2121
use futures::{FutureExt, future::select_ok};
2222
use reqwest::{
2323
Response, StatusCode,
2424
header::{ACCEPT, CONTENT_TYPE, USER_AGENT},
2525
};
26+
use ssz::Encode;
2627
use tracing::{debug, warn};
2728
use url::Url;
2829

2930
use crate::{
30-
constants::{
31-
MAX_SIZE_SUBMIT_BLOCK_RESPONSE, SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG, TIMEOUT_ERROR_CODE_STR,
32-
},
31+
TIMEOUT_ERROR_CODE_STR,
32+
constants::{MAX_SIZE_SUBMIT_BLOCK_RESPONSE, SUBMIT_BLINDED_BLOCK_ENDPOINT_TAG},
3333
metrics::{RELAY_LATENCY, RELAY_STATUS_CODE},
3434
state::{BuilderApiState, PbsState},
3535
};
@@ -65,6 +65,17 @@ pub async fn submit_block<S: BuilderApiState>(
6565
send_headers.insert(USER_AGENT, get_user_agent_with_version(&req_headers)?);
6666
send_headers.insert(HEADER_CONSENSUS_VERSION, consensus_version);
6767

68+
// Get the accept types from the request and forward them
69+
for value in req_headers.get_all(ACCEPT).iter() {
70+
send_headers.append(ACCEPT, value.clone());
71+
}
72+
73+
// Copy the content type header
74+
send_headers.insert(
75+
CONTENT_TYPE,
76+
HeaderValue::from_str(get_content_type(&req_headers).content_type()).unwrap(),
77+
);
78+
6879
let mut handles = Vec::with_capacity(state.all_relays().len());
6980
for relay in state.all_relays().iter().cloned() {
7081
handles.push(
@@ -180,15 +191,17 @@ async fn send_submit_block(
180191
// If the request only supports SSZ, but the relay only supports JSON, resubmit
181192
// to the relay with JSON - we'll convert it ourselves
182193
if code == StatusCode::NOT_ACCEPTABLE && accepts_ssz && !accepts_json {
194+
// TODO: needs to handle the case where the content-type is wrong too
183195
debug!(
184196
relay_id = relay.id.as_ref(),
185-
"relay does not support SSZ, resubmitting request with JSON accept header"
197+
"relay does not support SSZ, resubmitting request with JSON accept and content-type"
186198
);
187199

188-
// Resubmit the request with JSON accept header
200+
// Resubmit the request with JSON accept and content-type headers
189201
let elapsed = start_request.elapsed().as_millis() as u64;
190-
original_headers
191-
.insert(ACCEPT, HeaderValue::from_str(EncodingType::Json.content_type()).unwrap());
202+
let json_header_value = HeaderValue::from_str(EncodingType::Json.content_type()).unwrap();
203+
original_headers.insert(ACCEPT, json_header_value.clone());
204+
original_headers.insert(CONTENT_TYPE, json_header_value);
192205
start_request = Instant::now();
193206
(res, content_type) = send_submit_block_impl(
194207
url,
@@ -321,16 +334,16 @@ async fn send_submit_block_impl(
321334
headers: HeaderMap,
322335
timeout_ms: u64,
323336
) -> Result<(Response, Option<EncodingType>), PbsError> {
337+
// Get the content type of the request
338+
let content_type = get_content_type(&headers);
339+
324340
// Send the request
325-
let res = match relay
326-
.client
327-
.post(url)
328-
.timeout(Duration::from_millis(timeout_ms))
329-
.headers(headers)
330-
.json(&signed_blinded_block)
331-
.send()
332-
.await
333-
{
341+
let res = relay.client.post(url).timeout(Duration::from_millis(timeout_ms)).headers(headers);
342+
let body = match content_type {
343+
EncodingType::Json => serde_json::to_vec(&signed_blinded_block).unwrap(),
344+
EncodingType::Ssz => signed_blinded_block.as_ssz_bytes(),
345+
};
346+
let res = match res.body(body).header(CONTENT_TYPE, &content_type.to_string()).send().await {
334347
Ok(res) => res,
335348
Err(err) => {
336349
RELAY_STATUS_CODE

tests/src/mock_relay.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ use cb_common::{
2727
types::{BlsSecretKey, Chain},
2828
utils::{
2929
CONSENSUS_VERSION_HEADER, EncodingType, RawRequest, TestRandomSeed, deserialize_body,
30-
get_accept_types, get_consensus_version_header, timestamp_of_slot_start_sec,
30+
get_accept_types, get_consensus_version_header, get_content_type,
31+
timestamp_of_slot_start_sec,
3132
},
3233
};
3334
use cb_pbs::MAX_SIZE_SUBMIT_BLOCK_RESPONSE;
@@ -285,7 +286,15 @@ async fn handle_submit_block_v1(
285286
response
286287
}
287288

288-
async fn handle_submit_block_v2(State(state): State<Arc<MockRelayState>>) -> Response {
289+
async fn handle_submit_block_v2(
290+
headers: HeaderMap,
291+
State(state): State<Arc<MockRelayState>>,
292+
) -> Response {
289293
state.received_submit_block.fetch_add(1, Ordering::Relaxed);
294+
let content_type = get_content_type(&headers);
295+
if !state.supported_content_types.contains(&content_type) {
296+
return (StatusCode::NOT_ACCEPTABLE, "No acceptable content type found".to_string())
297+
.into_response();
298+
};
290299
(StatusCode::ACCEPTED, "").into_response()
291300
}

tests/tests/pbs_post_blinded_blocks.rs

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ async fn test_submit_block_v1() -> Result<()> {
2525
HashSet::from([EncodingType::Json]),
2626
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
2727
EncodingType::Json,
28+
1,
2829
)
2930
.await?;
3031
assert_eq!(res.status(), StatusCode::OK);
@@ -42,11 +43,12 @@ async fn test_submit_block_v1() -> Result<()> {
4243
#[tokio::test]
4344
async fn test_submit_block_v2() -> Result<()> {
4445
let res = submit_block_impl(
45-
3850,
46+
3810,
4647
BuilderApiVersion::V2,
4748
HashSet::from([EncodingType::Json]),
4849
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
4950
EncodingType::Json,
51+
1,
5052
)
5153
.await?;
5254
assert_eq!(res.status(), StatusCode::ACCEPTED);
@@ -57,11 +59,12 @@ async fn test_submit_block_v2() -> Result<()> {
5759
#[tokio::test]
5860
async fn test_submit_block_v1_ssz() -> Result<()> {
5961
let res = submit_block_impl(
60-
3810,
62+
3820,
6163
BuilderApiVersion::V1,
6264
HashSet::from([EncodingType::Ssz]),
6365
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
6466
EncodingType::Ssz,
67+
1,
6568
)
6669
.await?;
6770
assert_eq!(res.status(), StatusCode::OK);
@@ -80,18 +83,114 @@ async fn test_submit_block_v1_ssz() -> Result<()> {
8083
#[tokio::test]
8184
async fn test_submit_block_v2_ssz() -> Result<()> {
8285
let res = submit_block_impl(
83-
3860,
86+
3830,
8487
BuilderApiVersion::V2,
8588
HashSet::from([EncodingType::Ssz]),
8689
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
8790
EncodingType::Ssz,
91+
1,
8892
)
8993
.await?;
9094
assert_eq!(res.status(), StatusCode::ACCEPTED);
9195
assert_eq!(res.bytes().await?.len(), 0);
9296
Ok(())
9397
}
9498

99+
/// Test that a v1 submit block request in SSZ is converted to JSON if the relay
100+
/// only supports JSON
101+
#[tokio::test]
102+
async fn test_submit_block_v1_ssz_into_json() -> Result<()> {
103+
let res = submit_block_impl(
104+
3840,
105+
BuilderApiVersion::V1,
106+
HashSet::from([EncodingType::Ssz]),
107+
HashSet::from([EncodingType::Json]),
108+
EncodingType::Ssz,
109+
2,
110+
)
111+
.await?;
112+
assert_eq!(res.status(), StatusCode::OK);
113+
114+
let signed_blinded_block = load_test_signed_blinded_block();
115+
116+
let response_body =
117+
PayloadAndBlobs::from_ssz_bytes_by_fork(&res.bytes().await?, ForkName::Electra).unwrap();
118+
assert_eq!(
119+
response_body.execution_payload.block_hash(),
120+
signed_blinded_block.block_hash().into()
121+
);
122+
Ok(())
123+
}
124+
125+
/// Test that a v2 submit block request in SSZ is converted to JSON if the relay
126+
/// only supports JSON
127+
#[tokio::test]
128+
async fn test_submit_block_v2_ssz_into_json() -> Result<()> {
129+
let res = submit_block_impl(
130+
3850,
131+
BuilderApiVersion::V2,
132+
HashSet::from([EncodingType::Ssz]),
133+
HashSet::from([EncodingType::Json]),
134+
EncodingType::Ssz,
135+
2,
136+
)
137+
.await?;
138+
assert_eq!(res.status(), StatusCode::ACCEPTED);
139+
assert_eq!(res.bytes().await?.len(), 0);
140+
Ok(())
141+
}
142+
143+
/// Test v1 requesting multiple types when the relay supports SSZ, which should
144+
/// return SSZ
145+
#[tokio::test]
146+
async fn test_submit_block_v1_multitype_ssz() -> Result<()> {
147+
let res = submit_block_impl(
148+
3860,
149+
BuilderApiVersion::V1,
150+
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
151+
HashSet::from([EncodingType::Ssz]),
152+
EncodingType::Ssz,
153+
1,
154+
)
155+
.await?;
156+
assert_eq!(res.status(), StatusCode::OK);
157+
158+
let signed_blinded_block = load_test_signed_blinded_block();
159+
160+
let response_body =
161+
PayloadAndBlobs::from_ssz_bytes_by_fork(&res.bytes().await?, ForkName::Electra).unwrap();
162+
assert_eq!(
163+
response_body.execution_payload.block_hash(),
164+
signed_blinded_block.block_hash().into()
165+
);
166+
Ok(())
167+
}
168+
169+
/// Test v1 requesting multiple types when the relay supports SSZ, which should
170+
/// return JSON
171+
#[tokio::test]
172+
async fn test_submit_block_v1_multitype_json() -> Result<()> {
173+
let res = submit_block_impl(
174+
3870,
175+
BuilderApiVersion::V1,
176+
HashSet::from([EncodingType::Ssz, EncodingType::Json]),
177+
HashSet::from([EncodingType::Json]),
178+
EncodingType::Json,
179+
1,
180+
)
181+
.await?;
182+
assert_eq!(res.status(), StatusCode::OK);
183+
184+
let signed_blinded_block = load_test_signed_blinded_block();
185+
186+
let response_body = serde_json::from_slice::<SubmitBlindedBlockResponse>(&res.bytes().await?)?;
187+
assert_eq!(
188+
response_body.data.execution_payload.block_hash(),
189+
signed_blinded_block.block_hash().into()
190+
);
191+
Ok(())
192+
}
193+
95194
#[tokio::test]
96195
async fn test_submit_block_too_large() -> Result<()> {
97196
setup_test_env();
@@ -135,6 +234,7 @@ async fn submit_block_impl(
135234
accept_types: HashSet<EncodingType>,
136235
relay_types: HashSet<EncodingType>,
137236
serialization_mode: EncodingType,
237+
expected_try_count: u64,
138238
) -> Result<Response> {
139239
// Setup test environment
140240
setup_test_env();
@@ -184,6 +284,6 @@ async fn submit_block_impl(
184284
.await?
185285
}
186286
};
187-
assert_eq!(mock_state.received_submit_block(), 1);
287+
assert_eq!(mock_state.received_submit_block(), expected_try_count);
188288
Ok(res)
189289
}

0 commit comments

Comments
 (0)