@@ -308,12 +308,14 @@ pub(crate) fn build_data_column_sidecars<E: EthSpec>(
308308/// and it will be slow if the node needs to reconstruct the blobs
309309pub fn reconstruct_blobs < E : EthSpec > (
310310 kzg : & Kzg ,
311- data_columns : & [ Arc < DataColumnSidecar < E > > ] ,
311+ mut data_columns : Vec < Arc < DataColumnSidecar < E > > > ,
312312 blob_indices_opt : Option < Vec < u64 > > ,
313313 signed_block : & SignedBlindedBeaconBlock < E > ,
314314 spec : & ChainSpec ,
315315) -> Result < BlobSidecarList < E > , String > {
316- // The data columns are from the database, so we assume their correctness.
316+ // Sort data columns by index to ensure ascending order for KZG operations
317+ data_columns. sort_unstable_by_key ( |dc| dc. index ) ;
318+
317319 let first_data_column = data_columns
318320 . first ( )
319321 . ok_or ( "data_columns should have at least one element" . to_string ( ) ) ?;
@@ -331,7 +333,7 @@ pub fn reconstruct_blobs<E: EthSpec>(
331333 . map ( |row_index| {
332334 let mut cells: Vec < KzgCellRef > = vec ! [ ] ;
333335 let mut cell_ids: Vec < u64 > = vec ! [ ] ;
334- for data_column in data_columns {
336+ for data_column in & data_columns {
335337 let cell = data_column
336338 . column
337339 . get ( row_index)
@@ -463,6 +465,7 @@ mod test {
463465 test_reconstruct_data_columns ( & kzg, & spec) ;
464466 test_reconstruct_data_columns_unordered ( & kzg, & spec) ;
465467 test_reconstruct_blobs_from_data_columns ( & kzg, & spec) ;
468+ test_reconstruct_blobs_from_data_columns_unordered ( & kzg, & spec) ;
466469 test_validate_data_columns ( & kzg, & spec) ;
467470 }
468471
@@ -595,7 +598,7 @@ mod test {
595598 let blob_indices = vec ! [ 1 , 2 ] ;
596599 let reconstructed_blobs = reconstruct_blobs (
597600 kzg,
598- & column_sidecars. iter ( ) . as_slice ( ) [ 0 ..column_sidecars. len ( ) / 2 ] ,
601+ column_sidecars[ 0 ..column_sidecars. len ( ) / 2 ] . to_vec ( ) ,
599602 Some ( blob_indices. clone ( ) ) ,
600603 & signed_blinded_block,
601604 spec,
@@ -613,6 +616,31 @@ mod test {
613616 }
614617 }
615618
619+ #[ track_caller]
620+ fn test_reconstruct_blobs_from_data_columns_unordered ( kzg : & Kzg , spec : & ChainSpec ) {
621+ let num_of_blobs = 2 ;
622+ let ( signed_block, blobs, proofs) =
623+ create_test_fulu_block_and_blobs :: < E > ( num_of_blobs, spec) ;
624+ let blob_refs = blobs. iter ( ) . collect :: < Vec < _ > > ( ) ;
625+ let column_sidecars =
626+ blobs_to_data_column_sidecars ( & blob_refs, proofs. to_vec ( ) , & signed_block, kzg, spec)
627+ . unwrap ( ) ;
628+
629+ // Test reconstruction with columns in reverse order (non-ascending)
630+ let mut subset_columns: Vec < _ > =
631+ column_sidecars. iter ( ) . as_slice ( ) [ 0 ..column_sidecars. len ( ) / 2 ] . to_vec ( ) ;
632+ subset_columns. reverse ( ) ; // This would fail without proper sorting in reconstruct_blobs
633+
634+ let signed_blinded_block = signed_block. into ( ) ;
635+ let reconstructed_blobs =
636+ reconstruct_blobs ( kzg, subset_columns, None , & signed_blinded_block, spec) . unwrap ( ) ;
637+
638+ for ( i, original_blob) in blobs. iter ( ) . enumerate ( ) {
639+ let reconstructed_blob = & reconstructed_blobs. get ( i) . unwrap ( ) . blob ;
640+ assert_eq ! ( reconstructed_blob, original_blob, "{i}" ) ;
641+ }
642+ }
643+
616644 fn get_kzg ( ) -> Kzg {
617645 Kzg :: new_from_trusted_setup ( & get_trusted_setup ( ) ) . expect ( "should create kzg" )
618646 }
0 commit comments