Fix erasure (#10095)

* Fix bad FEC blocks

* Add test

Co-authored-by: Carl <carl@solana.com>
This commit is contained in:
carllin
2020-05-19 16:13:12 -07:00
committed by GitHub
parent e66b5d09db
commit 439fd30840
3 changed files with 189 additions and 45 deletions

View File

@@ -20,8 +20,8 @@ use solana_sdk::{
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
};
use std::mem::size_of;
use std::{sync::Arc, time::Instant};
use std::{mem::size_of, sync::Arc, time::Instant};
use thiserror::Error;
pub type Nonce = u32;
@@ -169,7 +169,7 @@ impl Shred {
index: u32,
parent_offset: u16,
data: Option<&[u8]>,
is_last_data: bool,
is_last_in_fec_set: bool,
is_last_in_slot: bool,
reference_tick: u8,
version: u16,
@@ -194,7 +194,7 @@ impl Shred {
size,
};
if is_last_data {
if is_last_in_fec_set {
data_header.flags |= DATA_COMPLETE_SHRED
}
@@ -496,7 +496,6 @@ impl Shredder {
let no_header_size = SIZE_OF_DATA_SHRED_PAYLOAD;
let num_shreds = (serialized_shreds.len() + no_header_size - 1) / no_header_size;
let last_shred_index = next_shred_index + num_shreds as u32 - 1;
// 1) Generate data shreds
let data_shreds: Vec<Shred> = PAR_THREAD_POOL.with(|thread_pool| {
thread_pool.borrow().install(|| {
@@ -511,7 +510,7 @@ impl Shredder {
let fec_set_index =
shred_index - (i % MAX_DATA_SHREDS_PER_FEC_BLOCK as usize) as u32;
let (is_last_data, is_last_in_slot) = {
let (is_last_in_fec_set, is_last_in_slot) = {
if shred_index == last_shred_index {
(true, is_last_in_slot)
} else {
@@ -524,7 +523,7 @@ impl Shredder {
shred_index,
(self.slot - self.parent_slot) as u16,
Some(shred_data),
is_last_data,
is_last_in_fec_set,
is_last_in_slot,
self.reference_tick,
self.version,
@@ -550,7 +549,6 @@ impl Shredder {
pub fn data_shreds_to_coding_shreds(&self, data_shreds: &[Shred]) -> Vec<Shred> {
let now = Instant::now();
let max_coding_shreds = data_shreds.len() > MAX_DATA_SHREDS_PER_FEC_BLOCK as usize;
// 2) Generate coding shreds
let mut coding_shreds: Vec<_> = PAR_THREAD_POOL.with(|thread_pool| {
thread_pool.borrow().install(|| {
@@ -562,7 +560,6 @@ impl Shredder {
self.fec_rate,
shred_data_batch,
self.version,
max_coding_shreds,
)
})
.collect()
@@ -630,25 +627,12 @@ impl Shredder {
fec_rate: f32,
data_shred_batch: &[Shred],
version: u16,
max_coding_shreds: bool,
) -> Vec<Shred> {
assert!(!data_shred_batch.is_empty());
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 shred_count = if max_coding_shreds {
MAX_DATA_SHREDS_PER_FEC_BLOCK as usize
} else {
num_data
};
let num_coding = Self::calculate_num_coding_shreds(shred_count as f32, 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, 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;
@@ -716,8 +700,12 @@ impl Shredder {
}
}
fn calculate_num_coding_shreds(num_data_shreds: f32, fec_rate: f32) -> usize {
1.max((fec_rate * num_data_shreds) as usize)
fn calculate_num_coding_shreds(num_data_shreds: usize, fec_rate: f32) -> usize {
if num_data_shreds == 0 {
0
} else {
num_data_shreds.min(1.max((fec_rate * num_data_shreds as f32) as usize))
}
}
fn fill_in_missing_shreds(
@@ -971,8 +959,7 @@ pub mod tests {
use bincode::serialized_size;
use matches::assert_matches;
use solana_sdk::{hash::hash, shred_version, system_transaction};
use std::collections::HashSet;
use std::convert::TryInto;
use std::{collections::HashSet, convert::TryInto};
#[test]
fn test_shred_constants() {
@@ -1061,7 +1048,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 f32, fec_rate);
Shredder::calculate_num_coding_shreds(num_expected_data_shreds as usize, fec_rate);
let start_index = 0;
let (data_shreds, coding_shreds, next_index) =
@@ -1640,7 +1627,7 @@ pub mod tests {
);
assert_eq!(
coding_shreds.len(),
MAX_DATA_SHREDS_PER_FEC_BLOCK as usize * 2
MAX_DATA_SHREDS_PER_FEC_BLOCK as usize + 1
);
}