Skip to content

Commit

Permalink
Merge pull request #3830 from jimmygchen/blobs-beacon-api
Browse files Browse the repository at this point in the history
Add Beacon API endpoint (/lighthouse) to download blobs by block ID
  • Loading branch information
realbigsean authored Jan 4, 2023
2 parents e02fcb3 + 11e3902 commit 8a77b05
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 1 deletion.
18 changes: 17 additions & 1 deletion beacon_node/http_api/src/block_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -211,6 +211,22 @@ impl BlockId {
}
}
}

/// Return the `BlobsSidecar` identified by `self`.
pub async fn blobs_sidecar<T: BeaconChainTypes>(
&self,
chain: &BeaconChain<T>,
) -> Result<(Arc<BlobsSidecar<T::EthSpec>>), warp::Rejection> {
let root = 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
))),
Err(e) => Err(warp_utils::reject::beacon_chain_error(e.into())),
}
}
}

impl FromStr for BlockId {
Expand Down
36 changes: 36 additions & 0 deletions beacon_node/http_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3324,6 +3324,41 @@ pub fn serve<T: BeaconChainTypes>(
)))
});

// GET lighthouse/beacon/blobs_sidecars/{block_id}
let get_lighthouse_blobs_sidecars = warp::path("lighthouse")
.and(warp::path("beacon"))
.and(warp::path("blobs_sidecars"))
.and(block_id_or_err)
.and(warp::path::end())
.and(chain_filter.clone())
.and(warp::header::optional::<api_types::Accept>("accept"))
.and_then(
|block_id: BlockId,
chain: Arc<BeaconChain<T>>,
accept_header: Option<api_types::Accept>| {
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())
Expand Down Expand Up @@ -3459,6 +3494,7 @@ pub fn serve<T: BeaconChainTypes>(
.or(get_lighthouse_attestation_performance.boxed())
.or(get_lighthouse_block_packing_efficiency.boxed())
.or(get_lighthouse_merge_readiness.boxed())
.or(get_lighthouse_blobs_sidecars.boxed())
.or(get_events.boxed()),
)
.boxed()
Expand Down
30 changes: 30 additions & 0 deletions common/eth2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,19 @@ impl BeaconNodeHttpClient {
Ok(path)
}

/// Path for `lighthouse/beacon/blobs_sidecars/{block_id}`
pub fn get_blobs_sidecar_path(&self, block_id: BlockId) -> Result<Url, Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("lighthouse")
.push("beacon")
.push("blobs_sidecars")
.push(&block_id.to_string());
Ok(path)
}

/// Path for `v1/beacon/blinded_blocks/{block_id}`
pub fn get_beacon_blinded_blocks_path(&self, block_id: BlockId) -> Result<Url, Error> {
let mut path = self.eth_path(V1)?;
Expand Down Expand Up @@ -735,6 +748,23 @@ impl BeaconNodeHttpClient {
}))
}

/// `GET lighthouse/beacon/blobs_sidecars/{block_id}`
///
/// Returns `Ok(None)` on a 404 error.
pub async fn get_blobs_sidecar<T: EthSpec>(
&self,
block_id: BlockId,
) -> Result<Option<GenericResponse<BlobsSidecar<T>>>, Error> {
let path = self.get_blobs_sidecar_path(block_id)?;
let response = match self.get_response(path, |b| b).await.optional()? {
Some(res) => res,
None => return Ok(None),
};

let GenericResponse { data } = response.json().await?;
Ok(Some(GenericResponse { data }))
}

/// `GET v1/beacon/blinded_blocks/{block_id}`
///
/// Returns `Ok(None)` on a 404 error.
Expand Down
1 change: 1 addition & 0 deletions lcli/src/parse_ssz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub fn run_parse_ssz<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
"state_merge" => decode_and_print::<BeaconStateMerge<T>>(&bytes, format)?,
"state_capella" => decode_and_print::<BeaconStateCapella<T>>(&bytes, format)?,
"state_eip4844" => decode_and_print::<BeaconStateEip4844<T>>(&bytes, format)?,
"blobs_sidecar" => decode_and_print::<BlobsSidecar<T>>(&bytes, format)?,
other => return Err(format!("Unknown type: {}", other)),
};

Expand Down

0 comments on commit 8a77b05

Please sign in to comment.