@@ -5,11 +5,16 @@ use anyhow::{bail, ensure, Result};
55use bls:: PublicKeyBytes ;
66use derive_more:: Constructor ;
77use helper_functions:: { misc, signing:: SignForAllForks } ;
8+ use http_api_utils:: ETH_CONSENSUS_VERSION ;
89use itertools:: Itertools as _;
910use log:: { debug, info} ;
11+ use mime:: { APPLICATION_JSON , APPLICATION_OCTET_STREAM } ;
1012use prometheus_metrics:: Metrics ;
11- use reqwest:: { Client , Response , StatusCode } ;
12- use ssz:: SszHash as _;
13+ use reqwest:: {
14+ header:: { ACCEPT , CONTENT_TYPE } ,
15+ Client , RequestBuilder , Response , StatusCode ,
16+ } ;
17+ use ssz:: { SszHash as _, SszRead as _, SszWrite as _} ;
1318use thiserror:: Error ;
1419use typenum:: Unsigned as _;
1520use types:: {
@@ -29,7 +34,7 @@ use crate::{
2934 combined:: { ExecutionPayloadAndBlobsBundle , SignedBuilderBid } ,
3035 consts:: BUILDER_PROPOSAL_DELAY_TOLERANCE ,
3136 unphased:: containers:: SignedValidatorRegistrationV1 ,
32- BuilderConfig ,
37+ BuilderApiFormat , BuilderConfig ,
3338} ;
3439
3540const REQUEST_TIMEOUT : Duration = Duration :: from_secs ( BUILDER_PROPOSAL_DELAY_TOLERANCE ) ;
@@ -157,19 +162,26 @@ impl Api {
157162 debug ! ( "getting execution payload header from {url}" ) ;
158163
159164 let response = self
160- . client
161- . get ( url. into_url ( ) )
162- . timeout ( REQUEST_TIMEOUT )
165+ . request_with_accept_header ( self . client . get ( url. into_url ( ) ) . timeout ( REQUEST_TIMEOUT ) )
163166 . send ( )
164167 . await ?;
168+
165169 let response = handle_error ( response) . await ?;
166170
167171 if response. status ( ) == StatusCode :: NO_CONTENT {
168172 info ! ( "builder has no execution payload header available for slot {slot}" ) ;
169173 return Ok ( None ) ;
170174 }
171175
172- let builder_bid = response. json :: < SignedBuilderBid < P > > ( ) . await ?;
176+ let builder_bid = match self . config . builder_api_format {
177+ BuilderApiFormat :: Json => response. json ( ) . await ?,
178+ BuilderApiFormat :: Ssz => {
179+ let phase = http_api_utils:: extract_phase_from_headers ( response. headers ( ) ) ?;
180+ let bytes = response. bytes ( ) . await ?;
181+
182+ SignedBuilderBid :: < P > :: from_ssz ( & phase, & bytes) ?
183+ }
184+ } ;
173185
174186 debug ! ( "get_execution_payload_header response: {builder_bid:?}" ) ;
175187
@@ -230,18 +242,33 @@ impl Api {
230242 let block_root = block. message ( ) . hash_tree_root ( ) ;
231243 let slot = block. message ( ) . slot ( ) ;
232244
233- let response = self
234- . client
235- . post ( url. into_url ( ) )
236- . json ( block)
237- . timeout ( remaining_time)
238- . send ( )
239- . await ?;
245+ let request = self . request_with_accept_header (
246+ self . client
247+ . post ( url. into_url ( ) )
248+ . timeout ( remaining_time)
249+ . header ( ETH_CONSENSUS_VERSION , block. phase ( ) . as_ref ( ) ) ,
250+ ) ;
251+
252+ let request = match self . config . builder_api_format {
253+ BuilderApiFormat :: Json => request. json ( block) ,
254+ BuilderApiFormat :: Ssz => request
255+ . header ( CONTENT_TYPE , APPLICATION_OCTET_STREAM . as_ref ( ) )
256+ . body ( block. to_ssz ( ) ?) ,
257+ } ;
240258
259+ let response = request. send ( ) . await ?;
241260 let response = handle_error ( response) . await ?;
242- let response: WithBlobsAndMev < ExecutionPayload < P > , P > = response
243- . json :: < ExecutionPayloadAndBlobsBundle < P > > ( )
244- . await ?
261+
262+ let response: WithBlobsAndMev < ExecutionPayload < P > , P > =
263+ match self . config . builder_api_format {
264+ BuilderApiFormat :: Json => response. json ( ) . await ?,
265+ BuilderApiFormat :: Ssz => {
266+ let phase = http_api_utils:: extract_phase_from_headers ( response. headers ( ) ) ?;
267+ let bytes = response. bytes ( ) . await ?;
268+
269+ ExecutionPayloadAndBlobsBundle :: < P > :: from_ssz ( & phase, & bytes) ?
270+ }
271+ }
245272 . into ( ) ;
246273
247274 let execution_payload = & response. value ;
@@ -266,6 +293,15 @@ impl Api {
266293 Ok ( response)
267294 }
268295
296+ fn request_with_accept_header ( & self , request_builder : RequestBuilder ) -> RequestBuilder {
297+ let accept_header = match self . config . builder_api_format {
298+ BuilderApiFormat :: Json => APPLICATION_JSON ,
299+ BuilderApiFormat :: Ssz => APPLICATION_OCTET_STREAM ,
300+ } ;
301+
302+ request_builder. header ( ACCEPT , accept_header. as_ref ( ) )
303+ }
304+
269305 fn url ( & self , path : & str ) -> Result < RedactingUrl > {
270306 self . config . builder_api_url . join ( path) . map_err ( Into :: into)
271307 }
@@ -345,6 +381,7 @@ mod tests {
345381 ) -> Result < ( ) , BuilderApiError > {
346382 let api = BuilderApi :: new (
347383 BuilderConfig {
384+ builder_api_format : BuilderApiFormat :: Json ,
348385 builder_api_url : "http://localhost"
349386 . parse ( )
350387 . expect ( "http://localhost should be a valid URL" ) ,
0 commit comments