Skip to content

Commit 74eec85

Browse files
committed
Add data columns sidecars debug beacon API.
1 parent 9803d69 commit 74eec85

File tree

3 files changed

+109
-2
lines changed

3 files changed

+109
-2
lines changed

beacon_node/http_api/src/block_id.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1+
use crate::version::inconsistent_fork_rejection;
12
use crate::{state_id::checkpoint_slot_and_execution_optimistic, ExecutionOptimistic};
23
use beacon_chain::kzg_utils::reconstruct_blobs;
34
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes, WhenSlotSkipped};
45
use eth2::types::BlobIndicesQuery;
56
use eth2::types::BlockId as CoreBlockId;
7+
use eth2::types::DataColumnIndicesQuery;
68
use std::fmt;
79
use std::str::FromStr;
810
use std::sync::Arc;
911
use types::{
10-
BlobSidecarList, EthSpec, FixedBytesExtended, Hash256, SignedBeaconBlock,
11-
SignedBlindedBeaconBlock, Slot,
12+
BlobSidecarList, DataColumnSidecarList, EthSpec, FixedBytesExtended, ForkName, Hash256,
13+
SignedBeaconBlock, SignedBlindedBeaconBlock, Slot,
1214
};
1315
use warp::Rejection;
1416

@@ -19,6 +21,13 @@ pub struct BlockId(pub CoreBlockId);
1921

2022
type Finalized = bool;
2123

24+
type DataColumnsResponse<T> = (
25+
DataColumnSidecarList<<T as BeaconChainTypes>::EthSpec>,
26+
ForkName,
27+
ExecutionOptimistic,
28+
Finalized,
29+
);
30+
2231
impl BlockId {
2332
pub fn from_slot(slot: Slot) -> Self {
2433
Self(CoreBlockId::Slot(slot))
@@ -260,6 +269,47 @@ impl BlockId {
260269
}
261270
}
262271

272+
pub fn get_data_columns<T: BeaconChainTypes>(
273+
&self,
274+
query: DataColumnIndicesQuery,
275+
chain: &BeaconChain<T>,
276+
) -> Result<DataColumnsResponse<T>, Rejection> {
277+
let (root, execution_optimistic, finalized) = self.root(chain)?;
278+
let block = BlockId::blinded_block_by_root(&root, chain)?.ok_or_else(|| {
279+
warp_utils::reject::custom_not_found(format!("beacon block with root {}", root))
280+
})?;
281+
282+
if chain.spec.is_peer_das_enabled_for_epoch(block.epoch()) {
283+
return Err(warp_utils::reject::custom_bad_request(
284+
"block is pre-Fulu and has no data columns".to_string(),
285+
));
286+
}
287+
288+
let data_column_sidecars = if let Some(indices) = query.indices {
289+
indices
290+
.iter()
291+
.filter_map(|index| chain.get_data_column(&root, index).transpose())
292+
.collect::<Result<DataColumnSidecarList<T::EthSpec>, _>>()
293+
.map_err(|e| warp_utils::reject::unhandled_error(e))?
294+
} else {
295+
chain
296+
.get_data_columns(&root)
297+
.map_err(|e| warp_utils::reject::unhandled_error(e))?
298+
.unwrap_or_default()
299+
};
300+
301+
let fork_name = block
302+
.fork_name(&chain.spec)
303+
.map_err(inconsistent_fork_rejection)?;
304+
305+
Ok((
306+
data_column_sidecars,
307+
fork_name,
308+
execution_optimistic,
309+
finalized,
310+
))
311+
}
312+
263313
#[allow(clippy::type_complexity)]
264314
pub fn get_blinded_block_and_blob_list_filtered<T: BeaconChainTypes>(
265315
&self,

beacon_node/http_api/src/lib.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2883,6 +2883,55 @@ pub fn serve<T: BeaconChainTypes>(
28832883
* debug
28842884
*/
28852885

2886+
// GET debug/beacon/data_column_sidecars/{block_id}
2887+
let get_debug_data_column_sidecars = eth_v1
2888+
.and(warp::path("debug"))
2889+
.and(warp::path("beacon"))
2890+
.and(warp::path("data_column_sidecars"))
2891+
.and(block_id_or_err)
2892+
.and(warp::path::end())
2893+
.and(multi_key_query::<api_types::DataColumnIndicesQuery>())
2894+
.and(task_spawner_filter.clone())
2895+
.and(chain_filter.clone())
2896+
.and(warp::header::optional::<api_types::Accept>("accept"))
2897+
.then(
2898+
|block_id: BlockId,
2899+
indices_res: Result<api_types::DataColumnIndicesQuery, warp::Rejection>,
2900+
task_spawner: TaskSpawner<T::EthSpec>,
2901+
chain: Arc<BeaconChain<T>>,
2902+
accept_header: Option<api_types::Accept>| {
2903+
task_spawner.blocking_response_task(Priority::P1, move || {
2904+
let indices = indices_res?;
2905+
let (data_columns, fork_name, execution_optimistic, finalized) =
2906+
block_id.get_data_columns(indices, &chain)?;
2907+
2908+
match accept_header {
2909+
Some(api_types::Accept::Ssz) => Response::builder()
2910+
.status(200)
2911+
.body(data_columns.as_ssz_bytes().into())
2912+
.map(|res: Response<Body>| add_ssz_content_type_header(res))
2913+
.map_err(|e| {
2914+
warp_utils::reject::custom_server_error(format!(
2915+
"failed to create response: {}",
2916+
e
2917+
))
2918+
}),
2919+
_ => {
2920+
// Post as a V2 endpoint so we return the fork version.
2921+
let res = execution_optimistic_finalized_beacon_response(
2922+
ResponseIncludesVersion::Yes(fork_name),
2923+
execution_optimistic,
2924+
finalized,
2925+
&data_columns,
2926+
)?;
2927+
Ok(warp::reply::json(&res).into_response())
2928+
}
2929+
}
2930+
.map(|resp| add_consensus_version_header(resp, fork_name))
2931+
})
2932+
},
2933+
);
2934+
28862935
// GET debug/beacon/states/{state_id}
28872936
let get_debug_beacon_states = any_version
28882937
.and(warp::path("debug"))
@@ -4950,6 +4999,7 @@ pub fn serve<T: BeaconChainTypes>(
49504999
.uor(get_config_spec)
49515000
.uor(get_config_deposit_contract)
49525001
.uor(get_debug_beacon_states)
5002+
.uor(get_debug_data_column_sidecars)
49535003
.uor(get_debug_beacon_heads)
49545004
.uor(get_debug_fork_choice)
49555005
.uor(get_node_identity)

common/eth2/src/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,13 @@ pub struct BlobIndicesQuery {
701701
pub indices: Option<Vec<u64>>,
702702
}
703703

704+
#[derive(Clone, Deserialize)]
705+
#[serde(deny_unknown_fields)]
706+
pub struct DataColumnIndicesQuery {
707+
#[serde(default, deserialize_with = "option_query_vec")]
708+
pub indices: Option<Vec<u64>>,
709+
}
710+
704711
#[derive(Clone, Serialize, Deserialize)]
705712
#[serde(transparent)]
706713
pub struct ValidatorIndexData(#[serde(with = "serde_utils::quoted_u64_vec")] pub Vec<u64>);

0 commit comments

Comments
 (0)