Skip to content

Commit 9d2f55a

Browse files
authored
Fix data column reconstruction error (sigp#7998)
Addresses sigp#7991
1 parent 677de70 commit 9d2f55a

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

beacon_node/beacon_chain/benches/benches.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn all_benches(c: &mut Criterion) {
5555
b.iter(|| {
5656
black_box(reconstruct_data_columns(
5757
&kzg,
58-
&column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2],
58+
column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2].to_vec(),
5959
spec.as_ref(),
6060
))
6161
})

beacon_node/beacon_chain/src/data_column_verification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ impl<E: EthSpec> KzgVerifiedCustodyDataColumn<E> {
376376
) -> Result<Vec<KzgVerifiedCustodyDataColumn<E>>, KzgError> {
377377
let all_data_columns = reconstruct_data_columns(
378378
kzg,
379-
&partial_set_of_columns
379+
partial_set_of_columns
380380
.iter()
381381
.map(|d| d.clone_arc())
382382
.collect::<Vec<_>>(),

beacon_node/beacon_chain/src/kzg_utils.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,18 @@ pub fn reconstruct_blobs<E: EthSpec>(
365365
/// Reconstruct all data columns from a subset of data column sidecars (requires at least 50%).
366366
pub fn reconstruct_data_columns<E: EthSpec>(
367367
kzg: &Kzg,
368-
data_columns: &[Arc<DataColumnSidecar<E>>],
368+
mut data_columns: Vec<Arc<DataColumnSidecar<E>>>,
369369
spec: &ChainSpec,
370370
) -> Result<DataColumnSidecarList<E>, KzgError> {
371+
// Sort data columns by index to ensure ascending order for KZG operations
372+
data_columns.sort_unstable_by_key(|dc| dc.index);
373+
371374
let first_data_column = data_columns
372375
.first()
373376
.ok_or(KzgError::InconsistentArrayLength(
374377
"data_columns should have at least one element".to_string(),
375378
))?;
379+
376380
let num_of_blobs = first_data_column.kzg_commitments.len();
377381

378382
let blob_cells_and_proofs_vec =
@@ -381,7 +385,7 @@ pub fn reconstruct_data_columns<E: EthSpec>(
381385
.map(|row_index| {
382386
let mut cells: Vec<KzgCellRef> = vec![];
383387
let mut cell_ids: Vec<u64> = vec![];
384-
for data_column in data_columns {
388+
for data_column in &data_columns {
385389
let cell = data_column.column.get(row_index).ok_or(
386390
KzgError::InconsistentArrayLength(format!(
387391
"Missing data column at row index {row_index}"
@@ -433,6 +437,7 @@ mod test {
433437
test_build_data_columns_empty(&kzg, &spec);
434438
test_build_data_columns(&kzg, &spec);
435439
test_reconstruct_data_columns(&kzg, &spec);
440+
test_reconstruct_data_columns_unordered(&kzg, &spec);
436441
test_reconstruct_blobs_from_data_columns(&kzg, &spec);
437442
test_validate_data_columns(&kzg, &spec);
438443
}
@@ -505,7 +510,7 @@ mod test {
505510

506511
#[track_caller]
507512
fn test_reconstruct_data_columns(kzg: &Kzg, spec: &ChainSpec) {
508-
let num_of_blobs = 6;
513+
let num_of_blobs = 2;
509514
let (signed_block, blobs, proofs) =
510515
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
511516
let blob_refs = blobs.iter().collect::<Vec<_>>();
@@ -516,7 +521,7 @@ mod test {
516521
// Now reconstruct
517522
let reconstructed_columns = reconstruct_data_columns(
518523
kzg,
519-
&column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2],
524+
column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2].to_vec(),
520525
spec,
521526
)
522527
.unwrap();
@@ -526,6 +531,27 @@ mod test {
526531
}
527532
}
528533

534+
#[track_caller]
535+
fn test_reconstruct_data_columns_unordered(kzg: &Kzg, spec: &ChainSpec) {
536+
let num_of_blobs = 2;
537+
let (signed_block, blobs, proofs) =
538+
create_test_fulu_block_and_blobs::<E>(num_of_blobs, spec);
539+
let blob_refs = blobs.iter().collect::<Vec<_>>();
540+
let column_sidecars =
541+
blobs_to_data_column_sidecars(&blob_refs, proofs.to_vec(), &signed_block, kzg, spec)
542+
.unwrap();
543+
544+
// Test reconstruction with columns in reverse order (non-ascending)
545+
let mut subset_columns: Vec<_> =
546+
column_sidecars.iter().as_slice()[0..column_sidecars.len() / 2].to_vec();
547+
subset_columns.reverse(); // This would fail without proper sorting in reconstruct_data_columns
548+
let reconstructed_columns = reconstruct_data_columns(kzg, subset_columns, spec).unwrap();
549+
550+
for i in 0..E::number_of_columns() {
551+
assert_eq!(reconstructed_columns.get(i), column_sidecars.get(i), "{i}");
552+
}
553+
}
554+
529555
#[track_caller]
530556
fn test_reconstruct_blobs_from_data_columns(kzg: &Kzg, spec: &ChainSpec) {
531557
let num_of_blobs = 6;

0 commit comments

Comments
 (0)