Implement /lighthouse/custody/info API (#8276)

Closes:

- https://github.com/sigp/lighthouse/issues/8249


  New `/lighthouse/custody` API including:

- [x] Earliest custodied data column slot
- [x] Node CGC
- [x] Custodied columns


Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Michael Sproul
2025-10-27 19:48:12 +11:00
committed by GitHub
parent ba706ce3bf
commit d67ae92112
6 changed files with 172 additions and 2 deletions

View File

@@ -0,0 +1,53 @@
use beacon_chain::{BeaconChain, BeaconChainTypes};
use eth2::lighthouse::CustodyInfo;
use std::sync::Arc;
use types::EthSpec;
use warp_utils::reject::{custom_bad_request, custom_server_error};
pub fn info<T: BeaconChainTypes>(
chain: Arc<BeaconChain<T>>,
) -> Result<CustodyInfo, warp::Rejection> {
if !chain.spec.is_fulu_scheduled() {
return Err(custom_bad_request("Fulu is not scheduled".to_string()));
}
let opt_data_column_custody_info = chain
.store
.get_data_column_custody_info()
.map_err(|e| custom_server_error(format!("error reading DataColumnCustodyInfo: {e:?}")))?;
let column_data_availability_boundary = chain
.column_data_availability_boundary()
.ok_or_else(|| custom_server_error("unreachable: Fulu should be enabled".to_string()))?;
let earliest_custodied_data_column_slot = opt_data_column_custody_info
.and_then(|info| info.earliest_data_column_slot)
.unwrap_or_else(|| {
// If there's no data column custody info/earliest data column slot, it means *column*
// backfill is not running. Block backfill could still be running, so our earliest
// available column is either the oldest block slot or the DA boundary, whichever is
// more recent.
let oldest_block_slot = chain.store.get_anchor_info().oldest_block_slot;
column_data_availability_boundary
.start_slot(T::EthSpec::slots_per_epoch())
.max(oldest_block_slot)
});
let earliest_custodied_data_column_epoch =
earliest_custodied_data_column_slot.epoch(T::EthSpec::slots_per_epoch());
// Compute the custody columns and the CGC *at the earliest custodied slot*. The node might
// have some columns prior to this, but this value is the most up-to-date view of the data the
// node is custodying.
let custody_context = chain.data_availability_checker.custody_context();
let custody_columns = custody_context
.custody_columns_for_epoch(Some(earliest_custodied_data_column_epoch), &chain.spec)
.to_vec();
let custody_group_count = custody_context
.custody_group_count_at_epoch(earliest_custodied_data_column_epoch, &chain.spec);
Ok(CustodyInfo {
earliest_custodied_data_column_slot,
custody_group_count,
custody_columns,
})
}

View File

@@ -13,6 +13,7 @@ mod block_packing_efficiency;
mod block_rewards;
mod build_block_contents;
mod builder_states;
mod custody;
mod database;
mod light_client;
mod metrics;
@@ -4590,6 +4591,19 @@ pub fn serve<T: BeaconChainTypes>(
},
);
// GET lighthouse/custody/info
let get_lighthouse_custody_info = warp::path("lighthouse")
.and(warp::path("custody"))
.and(warp::path("info"))
.and(warp::path::end())
.and(task_spawner_filter.clone())
.and(chain_filter.clone())
.then(
|task_spawner: TaskSpawner<T::EthSpec>, chain: Arc<BeaconChain<T>>| {
task_spawner.blocking_json_task(Priority::P1, move || custody::info(chain))
},
);
// GET lighthouse/analysis/block_rewards
let get_lighthouse_block_rewards = warp::path("lighthouse")
.and(warp::path("analysis"))
@@ -4891,6 +4905,7 @@ pub fn serve<T: BeaconChainTypes>(
.uor(get_lighthouse_validator_inclusion)
.uor(get_lighthouse_staking)
.uor(get_lighthouse_database_info)
.uor(get_lighthouse_custody_info)
.uor(get_lighthouse_block_rewards)
.uor(get_lighthouse_attestation_performance)
.uor(get_beacon_light_client_optimistic_update)