@@ -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%).
366366pub 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