diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 6b29017294e..9729297b111 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -358,6 +358,35 @@ pub fn serve( }, ); + // beacon/headers/{block_id} + let beacon_headers_block_id = base_path + .and(warp::path("beacon")) + .and(warp::path("headers")) + .and(warp::path::param::()) + .and(chain_filter.clone()) + .and_then(|block_id: BlockId, chain: Arc>| { + blocking_json_task(move || { + let root = block_id.root(&chain)?; + let block = BlockId::from_root(root).block(&chain)?; + + let canonical = chain + .block_root_at_slot(block.slot()) + .map_err(crate::reject::beacon_chain_error)? + .map_or(false, |canonical| root == canonical); + + let data = api_types::BlockHeaderData { + root, + canonical, + header: api_types::BlockHeaderAndSignature { + message: block.message.block_header(), + signature: block.signature.into(), + }, + }; + + Ok(api_types::GenericResponse::from(data)) + }) + }); + /* * beacon/blocks/{block_id} */ @@ -390,6 +419,7 @@ pub fn serve( .or(beacon_state_validators_id) .or(beacon_state_committees) .or(beacon_headers) + .or(beacon_headers_block_id) .or(beacon_block_root) .recover(crate::reject::handle_rejection); diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index e77f56b2ff4..4654b872853 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -219,6 +219,24 @@ impl BeaconNodeClient { self.get_opt(path).await } + /// `GET beacon/headers/{block_id}` + /// + /// Returns `Ok(None)` on a 404 error. + pub async fn beacon_headers_block_id( + &self, + block_id: BlockId, + ) -> Result>>, Error> { + let mut path = self.server.clone(); + + path.path_segments_mut() + .expect("path is base") + .push("beacon") + .push("headers") + .push(&block_id.to_string()); + + self.get_opt(path).await + } + /// `GET beacon/blocks/{block_id}/root` /// /// Returns `Ok(None)` on a 404 error.