diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 48803436ee..2fec64d948 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -5297,7 +5297,7 @@ pub mod tests { .iter() .cloned() .chain( - coding_shreds[coding_shreds.len() / 2 - 1..coding_shreds.len() / 2] + coding_shreds[coding_shreds.len() / 2 - 1..data_shreds.len() / 2] .iter() .cloned(), ) diff --git a/ledger/src/blockstore_meta.rs b/ledger/src/blockstore_meta.rs index 0148da0ab7..b599fd04cd 100644 --- a/ledger/src/blockstore_meta.rs +++ b/ledger/src/blockstore_meta.rs @@ -194,17 +194,19 @@ impl ErasureMeta { .data() .present_in_bounds(self.set_index..self.set_index + self.config.num_data() as u64); - let (data_missing, num_needed) = ( - self.config.num_data().saturating_sub(num_data), - self.config.num_data().saturating_sub(num_data + num_coding), + let (data_missing, coding_missing) = ( + self.config.num_data() - num_data, + self.config.num_coding() - num_coding, ); - if data_missing == 0 { - DataFull - } else if num_needed == 0 { + let total_missing = data_missing + coding_missing; + + if data_missing > 0 && total_missing <= self.config.num_coding() { CanRecover + } else if data_missing == 0 { + DataFull } else { - StillNeed(num_needed) + StillNeed(total_missing - self.config.num_coding()) } } diff --git a/ledger/src/shred.rs b/ledger/src/shred.rs index 4cb3087aaa..28fe2e3095 100644 --- a/ledger/src/shred.rs +++ b/ledger/src/shred.rs @@ -609,14 +609,7 @@ impl Shredder { if fec_rate != 0.0 { let num_data = data_shred_batch.len(); // always generate at least 1 coding shred even if the fec_rate doesn't allow it - let num_coding = Self::calculate_num_coding_shreds(num_data as u32, fec_rate); - if num_coding > num_data { - trace!( - "Generated more codes ({}) than data shreds ({})", - num_coding, - num_data - ); - } + let num_coding = Self::calculate_num_coding_shreds(num_data as f32, fec_rate); let session = Session::new(num_data, num_coding).expect("Failed to create erasure session"); let start_index = data_shred_batch[0].common_header.index; @@ -684,8 +677,8 @@ impl Shredder { } } - fn calculate_num_coding_shreds(num_data_shreds: u32, fec_rate: f32) -> usize { - (MAX_DATA_SHREDS_PER_FEC_BLOCK.max(num_data_shreds) as f32 * fec_rate) as usize + fn calculate_num_coding_shreds(num_data_shreds: f32, fec_rate: f32) -> usize { + 1.max((fec_rate * num_data_shreds) as usize) } fn fill_in_missing_shreds( @@ -994,7 +987,7 @@ pub mod tests { let no_header_size = SIZE_OF_DATA_SHRED_PAYLOAD as u64; let num_expected_data_shreds = (size + no_header_size - 1) / no_header_size; let num_expected_coding_shreds = - Shredder::calculate_num_coding_shreds(num_expected_data_shreds as u32, fec_rate); + Shredder::calculate_num_coding_shreds(num_expected_data_shreds as f32, fec_rate); let start_index = 0; let (data_shreds, coding_shreds, next_index) = @@ -1166,6 +1159,9 @@ pub mod tests { let (data_shreds, coding_shreds, _) = shredder.entries_to_shreds(&entries, true, 0); + // Must have created an equal number of coding and data shreds + assert_eq!(data_shreds.len(), coding_shreds.len()); + for (i, s) in data_shreds.iter().enumerate() { verify_test_data_shred( s, @@ -1210,10 +1206,10 @@ pub mod tests { let serialized_entries = bincode::serialize(&entries).unwrap(); let (data_shreds, coding_shreds, _) = shredder.entries_to_shreds(&entries, true, 0); - let num_coding_shreds = coding_shreds.len(); // We should have 10 shreds now, an equal number of coding shreds assert_eq!(data_shreds.len(), num_data_shreds); + assert_eq!(coding_shreds.len(), num_data_shreds); let all_shreds = data_shreds .iter() @@ -1226,7 +1222,7 @@ pub mod tests { Shredder::try_recovery( data_shreds[..data_shreds.len() - 1].to_vec(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 0, 0, slot @@ -1238,7 +1234,7 @@ pub mod tests { let recovered_data = Shredder::try_recovery( data_shreds[..].to_vec(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 0, 0, slot, @@ -1256,7 +1252,7 @@ pub mod tests { let mut recovered_data = Shredder::try_recovery( shred_info.clone(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 0, 0, slot, @@ -1304,7 +1300,7 @@ pub mod tests { let recovered_data = Shredder::try_recovery( shred_info.clone(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 0, 0, slot, @@ -1357,9 +1353,10 @@ pub mod tests { // and 2 missing coding shreds. Hint: should work let serialized_entries = bincode::serialize(&entries).unwrap(); let (data_shreds, coding_shreds, _) = shredder.entries_to_shreds(&entries, true, 25); - let num_coding_shreds = coding_shreds.len(); - // We should have 10 shreds now + + // We should have 10 shreds now, an equal number of coding shreds assert_eq!(data_shreds.len(), num_data_shreds); + assert_eq!(coding_shreds.len(), num_data_shreds); let all_shreds = data_shreds .iter() @@ -1376,7 +1373,7 @@ pub mod tests { let recovered_data = Shredder::try_recovery( shred_info.clone(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 25, 25, slot, @@ -1408,7 +1405,7 @@ pub mod tests { let recovered_data = Shredder::try_recovery( shred_info.clone(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 25, 25, slot + 1, @@ -1421,7 +1418,7 @@ pub mod tests { Shredder::try_recovery( shred_info.clone(), num_data_shreds, - num_coding_shreds, + num_data_shreds, 15, 15, slot, @@ -1431,7 +1428,7 @@ pub mod tests { // Test8: Try recovery/reassembly with incorrect index. Hint: does not recover any shreds assert_matches!( - Shredder::try_recovery(shred_info, num_data_shreds, num_coding_shreds, 35, 35, slot,), + Shredder::try_recovery(shred_info, num_data_shreds, num_data_shreds, 35, 35, slot,), Err(reed_solomon_erasure::Error::TooFewShardsPresent) ); }