diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 03f8fb7a2..f3c890d35 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -872,11 +872,35 @@ pub fn serve( .and(chain_filter.clone()); // GET beacon/blocks/{block_id} - let get_beacon_block = beacon_blocks_path.clone().and(warp::path::end()).and_then( - |block_id: BlockId, chain: Arc>| { - blocking_json_task(move || block_id.block(&chain).map(api_types::GenericResponse::from)) - }, - ); + let get_beacon_block = beacon_blocks_path + .clone() + .and(warp::path::end()) + .and(warp::header::optional::("accept")) + .and_then( + |block_id: BlockId, + chain: Arc>, + accept_header: Option| { + blocking_task(move || { + let block = block_id.block(&chain)?; + match accept_header { + Some(api_types::Accept::Ssz) => Response::builder() + .status(200) + .header("Content-Type", "application/octet-stream") + .body(block.as_ssz_bytes().into()) + .map_err(|e| { + warp_utils::reject::custom_server_error(format!( + "failed to create response: {}", + e + )) + }), + _ => Ok( + warp::reply::json(&api_types::GenericResponseRef::from(&block)) + .into_response(), + ), + } + }) + }, + ); // GET beacon/blocks/{block_id}/root let get_beacon_block_root = beacon_blocks_path diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index 65441b3e8..979158f01 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -955,16 +955,18 @@ impl ApiTester { pub async fn test_beacon_blocks(self) -> Self { for block_id in self.interesting_block_ids() { - let result = self + let expected = self.get_block(block_id); + + let json_result = self .client .get_beacon_blocks(block_id) .await .unwrap() .map(|res| res.data); + assert_eq!(json_result, expected, "{:?}", block_id); - let expected = self.get_block(block_id); - - assert_eq!(result, expected, "{:?}", block_id); + let ssz_result = self.client.get_beacon_blocks_ssz(block_id).await.unwrap(); + assert_eq!(ssz_result, expected, "{:?}", block_id); } self diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 94f1e7c5b..13c117b32 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -491,6 +491,27 @@ impl BeaconNodeHttpClient { self.get_opt(path).await } + /// `GET beacon/blocks` as SSZ + /// + /// Returns `Ok(None)` on a 404 error. + pub async fn get_beacon_blocks_ssz( + &self, + block_id: BlockId, + ) -> Result>, Error> { + let mut path = self.eth_path()?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("beacon") + .push("blocks") + .push(&block_id.to_string()); + + self.get_bytes_opt_accept_header(path, Accept::Ssz) + .await? + .map(|bytes| SignedBeaconBlock::from_ssz_bytes(&bytes).map_err(Error::InvalidSsz)) + .transpose() + } + /// `GET beacon/blocks/{block_id}/root` /// /// Returns `Ok(None)` on a 404 error.