Add Gloas data column support (#8682)

Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu>

Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com>
This commit is contained in:
Eitan Seri-Levi
2026-01-27 20:52:12 -08:00
committed by GitHub
parent 0f57fc9d8e
commit 9bec8df37a
44 changed files with 1507 additions and 680 deletions

View File

@@ -88,7 +88,11 @@ impl<E: EthSpec> BlockComponent<E> {
match self {
BlockComponent::Block(block) => block.value.parent_root(),
BlockComponent::Blob(blob) => blob.value.block_parent_root(),
BlockComponent::DataColumn(column) => column.value.block_parent_root(),
BlockComponent::DataColumn(column) => match column.value.as_ref() {
DataColumnSidecar::Fulu(column) => column.block_parent_root(),
// TODO(gloas) we don't have a parent root post gloas, not sure what to do here
DataColumnSidecar::Gloas(column) => column.beacon_block_root,
},
}
}
fn get_type(&self) -> &'static str {

View File

@@ -346,7 +346,7 @@ impl<E: EthSpec> RangeBlockComponentsRequest<E> {
for column in data_columns {
let block_root = column.block_root();
let index = column.index;
let index = *column.index();
if data_columns_by_block
.entry(block_root)
.or_default()
@@ -624,7 +624,7 @@ mod tests {
*req,
blocks
.iter()
.flat_map(|b| b.1.iter().filter(|d| d.index == column_index).cloned())
.flat_map(|b| b.1.iter().filter(|d| *d.index() == column_index).cloned())
.collect(),
)
.unwrap();
@@ -707,7 +707,7 @@ mod tests {
.iter()
.flat_map(|b| {
b.1.iter()
.filter(|d| column_indices.contains(&d.index))
.filter(|d| column_indices.contains(d.index()))
.cloned()
})
.collect::<Vec<_>>(),
@@ -779,7 +779,7 @@ mod tests {
*req,
blocks
.iter()
.flat_map(|b| b.1.iter().filter(|d| d.index == column_index).cloned())
.flat_map(|b| b.1.iter().filter(|d| *d.index() == column_index).cloned())
.collect(),
)
.unwrap();
@@ -864,7 +864,7 @@ mod tests {
*req1,
blocks
.iter()
.flat_map(|b| b.1.iter().filter(|d| d.index == 1).cloned())
.flat_map(|b| b.1.iter().filter(|d| *d.index() == 1).cloned())
.collect(),
)
.unwrap();
@@ -891,7 +891,7 @@ mod tests {
new_columns_req_id,
blocks
.iter()
.flat_map(|b| b.1.iter().filter(|d| d.index == 2).cloned())
.flat_map(|b| b.1.iter().filter(|d| *d.index() == 2).cloned())
.collect(),
)
.unwrap();
@@ -957,7 +957,7 @@ mod tests {
*req1,
blocks
.iter()
.flat_map(|b| b.1.iter().filter(|d| d.index == 1).cloned())
.flat_map(|b| b.1.iter().filter(|d| *d.index() == 1).cloned())
.collect(),
)
.unwrap();

View File

@@ -871,20 +871,28 @@ impl<T: BeaconChainTypes> SyncManager<T> {
SyncMessage::UnknownParentDataColumn(peer_id, data_column) => {
let data_column_slot = data_column.slot();
let block_root = data_column.block_root();
let parent_root = data_column.block_parent_root();
debug!(%block_root, %parent_root, "Received unknown parent data column message");
self.handle_unknown_parent(
peer_id,
block_root,
parent_root,
data_column_slot,
BlockComponent::DataColumn(DownloadResult {
value: data_column,
block_root,
seen_timestamp: timestamp_now(),
peer_group: PeerGroup::from_single(peer_id),
}),
);
match data_column.as_ref() {
DataColumnSidecar::Fulu(column) => {
let parent_root = column.block_parent_root();
debug!(%block_root, %parent_root, "Received unknown parent data column message");
self.handle_unknown_parent(
peer_id,
block_root,
parent_root,
data_column_slot,
BlockComponent::DataColumn(DownloadResult {
value: data_column,
block_root,
seen_timestamp: timestamp_now(),
peer_group: PeerGroup::from_single(peer_id),
}),
);
}
// TODO(gloas) support gloas data column variant
DataColumnSidecar::Gloas(_) => {
error!("Gloas variant not yet supported")
}
}
}
SyncMessage::UnknownBlockHashFromAttestation(peer_id, block_root) => {
if !self.notified_unknown_roots.contains(&(peer_id, block_root)) {

View File

@@ -127,7 +127,7 @@ impl<T: BeaconChainTypes> ActiveCustodyRequest<T> {
// requested index. The worse case is 128 loops over a 128 item vec + mutation to
// drop the consumed columns.
let mut data_columns = HashMap::<ColumnIndex, _>::from_iter(
data_columns.into_iter().map(|d| (d.index, d)),
data_columns.into_iter().map(|d| (*d.index(), d)),
);
// Accumulate columns that the peer does not have to issue a single log per request
let mut missing_column_indexes = vec![];
@@ -209,7 +209,7 @@ impl<T: BeaconChainTypes> ActiveCustodyRequest<T> {
peers
.entry(peer)
.or_default()
.push(data_column.index as usize);
.push(*data_column.index() as usize);
seen_timestamps.push(seen_timestamp);
Ok(data_column)
})

View File

@@ -28,18 +28,22 @@ impl<E: EthSpec> ActiveRequestItems for DataColumnsByRangeRequestItems<E> {
{
return Err(LookupVerifyError::UnrequestedSlot(data_column.slot()));
}
if !self.request.columns.contains(&data_column.index) {
return Err(LookupVerifyError::UnrequestedIndex(data_column.index));
if !self.request.columns.contains(data_column.index()) {
return Err(LookupVerifyError::UnrequestedIndex(*data_column.index()));
}
if !data_column.verify_inclusion_proof() {
if let DataColumnSidecar::Fulu(data_column) = data_column.as_ref()
&& !data_column.verify_inclusion_proof()
{
return Err(LookupVerifyError::InvalidInclusionProof);
}
if self.items.iter().any(|existing| {
existing.slot() == data_column.slot() && existing.index == data_column.index
existing.slot() == data_column.slot() && *existing.index() == *data_column.index()
}) {
return Err(LookupVerifyError::DuplicatedData(
data_column.slot(),
data_column.index,
*data_column.index(),
));
}

View File

@@ -56,16 +56,24 @@ impl<E: EthSpec> ActiveRequestItems for DataColumnsByRootRequestItems<E> {
if self.request.block_root != block_root {
return Err(LookupVerifyError::UnrequestedBlockRoot(block_root));
}
if !data_column.verify_inclusion_proof() {
if let DataColumnSidecar::Fulu(data_column) = data_column.as_ref()
&& !data_column.verify_inclusion_proof()
{
return Err(LookupVerifyError::InvalidInclusionProof);
}
if !self.request.indices.contains(&data_column.index) {
return Err(LookupVerifyError::UnrequestedIndex(data_column.index));
if !self.request.indices.contains(data_column.index()) {
return Err(LookupVerifyError::UnrequestedIndex(*data_column.index()));
}
if self.items.iter().any(|d| d.index == data_column.index) {
if self
.items
.iter()
.any(|d| *d.index() == *data_column.index())
{
return Err(LookupVerifyError::DuplicatedData(
data_column.slot(),
data_column.index,
*data_column.index(),
));
}

View File

@@ -189,9 +189,15 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
.unique()
.collect::<Vec<_>>();
// TODO(gloas) no block signatures to check post-gloas, double check what to do here
let column_block_signatures = columns
.iter()
.map(|column| column.signed_block_header.signature.clone())
.filter_map(|column| match column.as_ref() {
DataColumnSidecar::Fulu(column) => {
Some(column.signed_block_header.signature.clone())
}
_ => None,
})
.unique()
.collect::<Vec<_>>();
@@ -201,8 +207,8 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
// If there are no block roots, penalize all peers
[] => {
for column in &columns {
if let Some(naughty_peer) = column_to_peer.get(&column.index) {
naughty_peers.push((column.index, *naughty_peer));
if let Some(naughty_peer) = column_to_peer.get(column.index()) {
naughty_peers.push((*column.index(), *naughty_peer));
}
}
continue;
@@ -212,9 +218,9 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
for column in columns {
if column_block_roots.contains(&column.block_root())
&& block_root != column.block_root()
&& let Some(naughty_peer) = column_to_peer.get(&column.index)
&& let Some(naughty_peer) = column_to_peer.get(column.index())
{
naughty_peers.push((column.index, *naughty_peer));
naughty_peers.push((*column.index(), *naughty_peer));
}
}
continue;
@@ -227,17 +233,19 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
// If there are no block signatures, penalize all peers
[] => {
for column in &columns {
if let Some(naughty_peer) = column_to_peer.get(&column.index) {
naughty_peers.push((column.index, *naughty_peer));
if let Some(naughty_peer) = column_to_peer.get(column.index()) {
naughty_peers.push((*column.index(), *naughty_peer));
}
}
continue;
}
// If theres more than one unique block signature, penalize the peers serving the
// invalid block signatures.
// invalid block signatures. This check is only relevant for Fulu.
column_block_signatures => {
for column in columns {
if column_block_signatures.contains(&column.signed_block_header.signature)
if let DataColumnSidecar::Fulu(column) = column.as_ref()
&& column_block_signatures
.contains(&column.signed_block_header.signature)
&& block.signature() != &column.signed_block_header.signature
&& let Some(naughty_peer) = column_to_peer.get(&column.index)
{
@@ -251,8 +259,8 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
// if the block root doesn't match the columns block root, penalize the peers
if block_root != column_block_root {
for column in &columns {
if let Some(naughty_peer) = column_to_peer.get(&column.index) {
naughty_peers.push((column.index, *naughty_peer));
if let Some(naughty_peer) = column_to_peer.get(column.index()) {
naughty_peers.push((*column.index(), *naughty_peer));
}
}
}
@@ -260,13 +268,13 @@ impl<T: BeaconChainTypes> RangeDataColumnBatchRequest<T> {
// If the block signature doesn't match the columns block signature, penalize the peers
if block.signature() != column_block_signature {
for column in &columns {
if let Some(naughty_peer) = column_to_peer.get(&column.index) {
naughty_peers.push((column.index, *naughty_peer));
if let Some(naughty_peer) = column_to_peer.get(column.index()) {
naughty_peers.push((*column.index(), *naughty_peer));
}
}
}
let received_columns = columns.iter().map(|c| c.index).collect::<HashSet<_>>();
let received_columns = columns.iter().map(|c| *c.index()).collect::<HashSet<_>>();
let missing_columns = expected_custody_columns
.difference(&received_columns)

View File

@@ -393,7 +393,7 @@ impl TestRig {
let data_sidecars = if fork.fulu_enabled() {
store
.get_data_columns(&block_root)
.get_data_columns(&block_root, fork)
.unwrap()
.map(|columns| {
columns