Merge remote-tracking branch, resolve conflicts preserving FOCIL/Heze logic

- test_utils: Heze branch uses DataColumnSidecarGloas (shared format), keeps
  heze_enabled() check ahead of gloas_enabled() so Heze blocks are handled first
- genesis.rs: Keep both Gloas and Heze bid initialisation in genesis_block()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Eitan Seri-Levi
2026-04-30 10:04:04 +02:00
12 changed files with 33 additions and 180 deletions

View File

@@ -8,10 +8,7 @@ use crate::custody_context::NodeCustodyType;
use crate::data_availability_checker::DataAvailabilityChecker;
use crate::fork_choice_signal::ForkChoiceSignalTx;
use crate::graffiti_calculator::{GraffitiCalculator, GraffitiOrigin};
use crate::kzg_utils::{
build_data_column_sidecars_fulu, build_data_column_sidecars_gloas,
build_data_column_sidecars_heze,
};
use crate::kzg_utils::{build_data_column_sidecars_fulu, build_data_column_sidecars_gloas};
use crate::light_client_server_cache::LightClientServerCache;
use crate::migrate::{BackgroundMigrator, MigratorConfig};
use crate::observed_data_sidecars::ObservedDataSidecars;
@@ -1240,15 +1237,7 @@ fn build_data_columns_from_blobs<E: EthSpec>(
.cloned()
.map_err(|e| format!("Unexpected pre Deneb block: {e:?}"))?;
if block.fork_name_unchecked().heze_enabled() {
build_data_column_sidecars_heze(
block.message().tree_hash_root(),
block.slot(),
blob_cells_and_proofs_vec,
spec,
)
.map_err(|e| format!("Failed to compute weak subjectivity data_columns: {e:?}"))?
} else if block.fork_name_unchecked().gloas_enabled() {
if block.fork_name_unchecked().gloas_enabled() {
build_data_column_sidecars_gloas(
block.message().tree_hash_root(),
block.slot(),

View File

@@ -320,9 +320,7 @@ impl<T: BeaconChainTypes, O: ObservationStrategy> GossipVerifiedDataColumn<T, O>
})
}
// TODO(gloas) support gloas data column variant
DataColumnSidecar::Gloas(_) | DataColumnSidecar::Heze(_) => {
Err(GossipDataColumnError::InvalidVariant)
}
DataColumnSidecar::Gloas(_) => Err(GossipDataColumnError::InvalidVariant),
}
}
@@ -1131,9 +1129,7 @@ fn verify_data_column_sidecar<E: EthSpec>(
// TODO(gloas): implement Gloas verification that takes kzg_commitments from block as parameter
let commitments_len = match data_column {
DataColumnSidecar::Fulu(dc) => dc.kzg_commitments.len(),
DataColumnSidecar::Gloas(_) | DataColumnSidecar::Heze(_) => {
return Err(GossipDataColumnError::InvalidVariant);
}
DataColumnSidecar::Gloas(_) => return Err(GossipDataColumnError::InvalidVariant),
};
if commitments_len == 0 {

View File

@@ -13,9 +13,8 @@ use types::data::{
use types::kzg_ext::KzgCommitments;
use types::{
Blob, BlobSidecar, BlobSidecarList, ChainSpec, DataColumnSidecar, DataColumnSidecarFulu,
DataColumnSidecarGloas, DataColumnSidecarHeze, DataColumnSidecarList, EthSpec, Hash256,
KzgCommitment, KzgProof, SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlindedBeaconBlock,
Slot,
DataColumnSidecarGloas, DataColumnSidecarList, EthSpec, Hash256, KzgCommitment, KzgProof,
SignedBeaconBlock, SignedBeaconBlockHeader, SignedBlindedBeaconBlock, Slot,
};
/// Converts a blob ssz FixedVector to a reference to a fixed-size array
@@ -81,11 +80,11 @@ pub fn validate_full_data_columns<'a, E: EthSpec>(
// This function requires Fulu sidecars with embedded commitments.
let kzg_commitments = match data_column.as_ref() {
DataColumnSidecar::Fulu(dc) => &dc.kzg_commitments,
DataColumnSidecar::Gloas(_) | DataColumnSidecar::Heze(_) => {
DataColumnSidecar::Gloas(_) => {
return Err((
Some(col_index),
KzgError::InconsistentArrayLength(
"Gloas/Heze data columns require commitments from block".to_string(),
"Gloas data columns require commitments from block".to_string(),
),
));
}
@@ -275,15 +274,7 @@ pub fn blobs_to_data_column_sidecars<E: EthSpec>(
})
.collect::<Result<Vec<_>, KzgError>>()?;
if block.fork_name_unchecked().heze_enabled() {
build_data_column_sidecars_heze(
signed_block_header.message.tree_hash_root(),
block.slot(),
blob_cells_and_proofs_vec,
spec,
)
.map_err(DataColumnSidecarError::BuildSidecarFailed)
} else if block.fork_name_unchecked().gloas_enabled() {
if block.fork_name_unchecked().gloas_enabled() {
build_data_column_sidecars_gloas(
signed_block_header.message.tree_hash_root(),
block.slot(),
@@ -403,7 +394,7 @@ pub(crate) fn build_data_column_sidecars_fulu<E: EthSpec>(
.fork_name_at_slot::<E>(signed_block_header.message.slot)
.gloas_enabled()
{
return Err("Attempting to construct Fulu data columns post-Gloas/Heze".to_owned());
return Err("Attempting to construct Fulu data columns post-Gloas".to_owned());
}
let number_of_columns = E::number_of_columns();
@@ -528,68 +519,6 @@ pub(crate) fn build_data_column_sidecars_gloas<E: EthSpec>(
sidecars
}
pub(crate) fn build_data_column_sidecars_heze<E: EthSpec>(
beacon_block_root: Hash256,
slot: Slot,
blob_cells_and_proofs_vec: Vec<CellsAndKzgProofs>,
spec: &ChainSpec,
) -> Result<DataColumnSidecarList<E>, String> {
if !spec.fork_name_at_slot::<E>(slot).heze_enabled() {
return Err("Attempting to construct Heze data columns pre-Heze".to_owned());
}
let number_of_columns = E::number_of_columns();
let max_blobs_per_block = spec.max_blobs_per_block(slot.epoch(E::slots_per_epoch())) as usize;
let mut columns = vec![Vec::with_capacity(max_blobs_per_block); number_of_columns];
let mut column_kzg_proofs = vec![Vec::with_capacity(max_blobs_per_block); number_of_columns];
for (blob_cells, blob_cell_proofs) in blob_cells_and_proofs_vec {
for col in 0..number_of_columns {
let cell = blob_cells
.get(col)
.ok_or(format!("Missing blob cell at index {col}"))?;
let cell: Vec<u8> = cell.to_vec();
let cell =
Cell::<E>::try_from(cell).map_err(|e| format!("BytesPerCell exceeded: {e:?}"))?;
let proof = blob_cell_proofs
.get(col)
.ok_or(format!("Missing blob cell KZG proof at index {col}"))?;
let column = columns
.get_mut(col)
.ok_or(format!("Missing data column at index {col}"))?;
let column_proofs = column_kzg_proofs
.get_mut(col)
.ok_or(format!("Missing data column proofs at index {col}"))?;
column.push(cell);
column_proofs.push(*proof);
}
}
let sidecars: Result<Vec<Arc<DataColumnSidecar<E>>>, String> = columns
.into_iter()
.zip(column_kzg_proofs)
.enumerate()
.map(
|(index, (col, proofs))| -> Result<Arc<DataColumnSidecar<E>>, String> {
Ok(Arc::new(DataColumnSidecar::Heze(DataColumnSidecarHeze {
index: index as u64,
column: DataColumn::<E>::try_from(col)
.map_err(|e| format!("MaxBlobCommitmentsPerBlock exceeded: {e:?}"))?,
kzg_proofs: VariableList::try_from(proofs)
.map_err(|e| format!("MaxBlobCommitmentsPerBlock exceeded: {e:?}"))?,
beacon_block_root,
slot,
})))
},
)
.collect();
sidecars
}
pub(crate) fn build_partial_data_columns<E: EthSpec>(
header: &PartialDataColumnHeader<E>,
blob_cells_and_proofs_vec: Vec<Option<CellsAndKzgProofs>>,
@@ -700,7 +629,7 @@ pub fn reconstruct_blobs<E: EthSpec>(
// https://github.com/sigp/lighthouse/issues/7413
let num_of_blobs = first_data_column
.kzg_commitments()
.map_err(|_| "Gloas/Heze blob reconstruction not yet supported".to_string())?
.map_err(|_| "Gloas blob reconstruction not yet supported".to_string())?
.len();
(0..num_of_blobs).collect()
}
@@ -780,7 +709,7 @@ pub fn reconstruct_data_columns<E: EthSpec>(
.kzg_commitments()
.map_err(|_| {
KzgError::InconsistentArrayLength(
"Gloas/Heze data column reconstruction not yet supported".to_string(),
"Gloas data column reconstruction not yet supported".to_string(),
)
})?
.len();
@@ -822,13 +751,6 @@ pub fn reconstruct_data_columns<E: EthSpec>(
spec,
)
.map_err(KzgError::ReconstructFailed),
DataColumnSidecar::Heze(first_column) => build_data_column_sidecars_heze(
first_column.beacon_block_root,
first_column.slot,
blob_cells_and_proofs_vec,
spec,
)
.map_err(KzgError::ReconstructFailed),
}
}

View File

@@ -265,8 +265,8 @@ mod tests {
use bls::{FixedBytesExtended, Signature};
use std::sync::Arc;
use types::{
BeaconBlockHeader, DataColumnSidecarFulu, DataColumnSidecarGloas, DataColumnSidecarHeze,
ForkName, MainnetEthSpec, SignedBeaconBlockHeader,
BeaconBlockHeader, DataColumnSidecarFulu, DataColumnSidecarGloas, ForkName, MainnetEthSpec,
SignedBeaconBlockHeader,
};
type E = MainnetEthSpec;
@@ -320,31 +320,13 @@ mod tests {
}))
}
/// Creates a Heze DataColumnSidecar for testing.
/// Keyed by (beacon_block_root, slot) in the observation cache.
fn get_data_column_sidecar_heze(
slot: u64,
beacon_block_root: Hash256,
index: u64,
) -> Arc<DataColumnSidecar<E>> {
Arc::new(DataColumnSidecar::Heze(DataColumnSidecarHeze {
index,
column: vec![].try_into().unwrap(),
kzg_proofs: vec![].try_into().unwrap(),
slot: slot.into(),
beacon_block_root,
}))
}
fn get_sidecar(
slot: u64,
key: u64,
index: u64,
fork_name: ForkName,
) -> Arc<DataColumnSidecar<E>> {
if fork_name.heze_enabled() {
get_data_column_sidecar_heze(slot, Hash256::from_low_u64_be(key), index)
} else if fork_name.gloas_enabled() {
if fork_name.gloas_enabled() {
get_data_column_sidecar_gloas(slot, Hash256::from_low_u64_be(key), index)
} else {
get_data_column_sidecar_fulu(slot, key, index)

View File

@@ -3,10 +3,7 @@ use crate::block_verification_types::{AsBlock, AvailableBlockData, LookupBlock,
use crate::custody_context::NodeCustodyType;
use crate::data_availability_checker::DataAvailabilityChecker;
use crate::graffiti_calculator::GraffitiSettings;
use crate::kzg_utils::{
build_data_column_sidecars_fulu, build_data_column_sidecars_gloas,
build_data_column_sidecars_heze,
};
use crate::kzg_utils::{build_data_column_sidecars_fulu, build_data_column_sidecars_gloas};
use crate::observed_operations::ObservationOutcome;
pub use crate::persisted_beacon_chain::PersistedBeaconChain;
use crate::{BeaconBlockResponseWrapper, CustodyContext, get_block_root};
@@ -3894,8 +3891,8 @@ pub fn generate_data_column_sidecars_from_block<E: EthSpec>(
let num_blobs = kzg_commitments.len();
let signed_block_header = block.signed_block_header();
let template_data_columns =
RuntimeVariableList::<DataColumnSidecarHeze<E>>::from_ssz_bytes(
TEST_DATA_COLUMN_SIDECARS_SSZ,
RuntimeVariableList::<DataColumnSidecarGloas<E>>::from_ssz_bytes(
TEST_DATA_COLUMN_SIDECARS_GLOAS_SSZ,
E::number_of_columns(),
)
.unwrap();
@@ -3903,7 +3900,7 @@ pub fn generate_data_column_sidecars_from_block<E: EthSpec>(
let (cells, proofs) = template_data_columns
.into_iter()
.map(|sidecar| {
let DataColumnSidecarHeze {
let DataColumnSidecarGloas {
column, kzg_proofs, ..
} = sidecar;
// There's only one cell per column for a single blob
@@ -3917,7 +3914,7 @@ pub fn generate_data_column_sidecars_from_block<E: EthSpec>(
let blob_cells_and_proofs_vec =
vec![(cells.try_into().unwrap(), proofs.try_into().unwrap()); num_blobs];
build_data_column_sidecars_heze(
build_data_column_sidecars_gloas(
signed_block_header.message.tree_hash_root(),
signed_block_header.message.slot,
blob_cells_and_proofs_vec,