From 70d6e6705e86b1aed18e31e7887760845a62df93 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Fri, 23 Dec 2022 12:42:00 +1100 Subject: [PATCH] Add Beacon API endpoint to download blobs by block ID --- beacon_node/http_api/src/block_id.rs | 47 +++++++++++++++++++++++++++- beacon_node/http_api/src/lib.rs | 35 +++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/beacon_node/http_api/src/block_id.rs b/beacon_node/http_api/src/block_id.rs index 5c785fe65..2578b4a67 100644 --- a/beacon_node/http_api/src/block_id.rs +++ b/beacon_node/http_api/src/block_id.rs @@ -4,7 +4,7 @@ use eth2::types::BlockId as CoreBlockId; use std::fmt; use std::str::FromStr; use std::sync::Arc; -use types::{Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot}; +use types::{BlobsSidecar, Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot}; /// Wraps `eth2::types::BlockId` and provides a simple way to obtain a block or root for a given /// `BlockId`. @@ -211,6 +211,51 @@ impl BlockId { } } } + + /// Return the `BlobsSidecar` identified by `self`. + pub async fn blobs_sidecar( + &self, + chain: &BeaconChain, + ) -> Result<(Arc>), warp::Rejection> { + let root = match &self.0 { + CoreBlockId::Head => { + let (cached_head, _execution_status) = chain + .canonical_head + .head_and_execution_status() + .map_err(warp_utils::reject::beacon_chain_error)?; + cached_head.head_block_root() + } + CoreBlockId::Slot(slot) => { + let maybe_block_root = chain + .block_root_at_slot(*slot, WhenSlotSkipped::None) + .ok() + .flatten(); + match maybe_block_root { + Some(block_root) => block_root, + None => { + return Err(warp_utils::reject::custom_not_found(format!( + "Block root for slot {} not found", + slot + ))) + } + } + } + _ => self.root(chain)?.0, + }; + + match chain.store.get_blobs(&root) { + Ok(Some(blob)) => Ok((Arc::new(blob))), + Ok(None) => Err(warp_utils::reject::custom_not_found(format!( + "Blob with block root {} is not in the store", + root + ))), + // should we use `warp_utils::reject::beacon_chain_error` instead? + Err(e) => Err(warp_utils::reject::custom_not_found(format!( + "Error fetching blob with block root {}: {:?}", + root, e + ))), + } + } } impl FromStr for BlockId { diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index e5336ef6a..6caf99a07 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -3324,6 +3324,41 @@ pub fn serve( ))) }); + // GET lighthouse/beacon/blob_sidecars/{block_id} + let get_blob_sidecars = warp::path("lighthouse") + .and(warp::path("beacon")) + .and(warp::path("blob_sidecars")) + .and(block_id_or_err) + .and(warp::path::end()) + .and(chain_filter.clone()) + .and(warp::header::optional::("accept")) + .and_then( + |block_id: BlockId, + chain: Arc>, + accept_header: Option| { + async move { + let blobs_sidecar = block_id.blobs_sidecar(&chain).await?; + + match accept_header { + Some(api_types::Accept::Ssz) => Response::builder() + .status(200) + .header("Content-Type", "application/octet-stream") + .body(blobs_sidecar.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::GenericResponse::from( + blobs_sidecar, + )) + .into_response()), + } + } + }, + ); + let get_events = eth_v1 .and(warp::path("events")) .and(warp::path::end())