Add a version field to shreds (#7023)

* Add a version field to shreds

* Clippy

* Fix Chacha Golden

* Fix shredder bench compile

* Fix blocktree bench compile
This commit is contained in:
Sagar Dhawan
2019-11-18 18:05:02 -08:00
committed by GitHub
parent bfa2535ea1
commit 6bfe0fca1f
21 changed files with 235 additions and 81 deletions

View File

@ -941,6 +941,8 @@ impl Blocktree {
self.code_shred_cf.get_bytes((slot, index))
}
// Only used by tests
#[allow(clippy::too_many_arguments)]
pub fn write_entries(
&self,
start_slot: Slot,
@ -951,6 +953,7 @@ impl Blocktree {
is_full_slot: bool,
keypair: &Arc<Keypair>,
entries: Vec<Entry>,
version: u16,
) -> Result<usize> {
let mut parent_slot = parent.map_or(start_slot.saturating_sub(1), |v| v);
let num_slots = (start_slot - parent_slot).max(1); // Note: slot 0 has parent slot 0
@ -958,8 +961,9 @@ impl Blocktree {
let mut remaining_ticks_in_slot = num_slots * ticks_per_slot - num_ticks_in_start_slot;
let mut current_slot = start_slot;
let mut shredder = Shredder::new(current_slot, parent_slot, 0.0, keypair.clone(), 0)
.expect("Failed to create entry shredder");
let mut shredder =
Shredder::new(current_slot, parent_slot, 0.0, keypair.clone(), 0, version)
.expect("Failed to create entry shredder");
let mut all_shreds = vec![];
let mut slot_entries = vec![];
// Find all the entries for start_slot
@ -987,6 +991,7 @@ impl Blocktree {
0.0,
keypair.clone(),
(ticks_per_slot - remaining_ticks_in_slot) as u8,
version,
)
.expect("Failed to create entry shredder");
}
@ -1833,8 +1838,9 @@ pub fn create_new_ledger(ledger_path: &Path, genesis_config: &GenesisConfig) ->
let hashes_per_tick = genesis_config.poh_config.hashes_per_tick.unwrap_or(0);
let entries = create_ticks(ticks_per_slot, hashes_per_tick, genesis_config.hash());
let last_hash = entries.last().unwrap().hash;
let version = Shred::version_from_hash(&last_hash);
let shredder = Shredder::new(0, 0, 0.0, Arc::new(Keypair::new()), 0)
let shredder = Shredder::new(0, 0, 0.0, Arc::new(Keypair::new()), 0, version)
.expect("Failed to create entry shredder");
let shreds = shredder.entries_to_shreds(&entries, true, 0).0;
assert!(shreds.last().unwrap().last_in_slot());
@ -1918,8 +1924,9 @@ pub fn entries_to_test_shreds(
slot: Slot,
parent_slot: Slot,
is_full_slot: bool,
version: u16,
) -> Vec<Shred> {
let shredder = Shredder::new(slot, parent_slot, 0.0, Arc::new(Keypair::new()), 0)
let shredder = Shredder::new(slot, parent_slot, 0.0, Arc::new(Keypair::new()), 0, version)
.expect("Failed to create entry shredder");
shredder.entries_to_shreds(&entries, is_full_slot, 0).0
@ -1932,7 +1939,7 @@ pub fn make_slot_entries(
num_entries: u64,
) -> (Vec<Shred>, Vec<Entry>) {
let entries = create_ticks(num_entries, 0, Hash::default());
let shreds = entries_to_test_shreds(entries.clone(), slot, parent_slot, true);
let shreds = entries_to_test_shreds(entries.clone(), slot, parent_slot, true, 0);
(shreds, entries)
}
@ -2056,7 +2063,7 @@ pub mod tests {
let mut tick = create_ticks(1, 0, Hash::default());
entries.append(&mut tick);
}
let shreds = entries_to_test_shreds(entries.clone(), slot, parent_slot, true);
let shreds = entries_to_test_shreds(entries.clone(), slot, parent_slot, true, 0);
(shreds, entries)
}
@ -2132,6 +2139,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
new_ticks.clone(),
0,
)
.unwrap() as u64;
shreds_per_slot.push(num_shreds);
@ -2452,12 +2460,12 @@ pub mod tests {
{
let blocktree = Blocktree::open(&blocktree_path).unwrap();
let entries = create_ticks(8, 0, Hash::default());
let shreds = entries_to_test_shreds(entries[0..4].to_vec(), 1, 0, false);
let shreds = entries_to_test_shreds(entries[0..4].to_vec(), 1, 0, false, 0);
blocktree
.insert_shreds(shreds, None, false)
.expect("Expected successful write of shreds");
let mut shreds1 = entries_to_test_shreds(entries[4..].to_vec(), 1, 0, false);
let mut shreds1 = entries_to_test_shreds(entries[4..].to_vec(), 1, 0, false, 0);
for (i, b) in shreds1.iter_mut().enumerate() {
b.set_index(8 + i as u32);
}
@ -2489,7 +2497,7 @@ pub mod tests {
let entries = create_ticks(slot + 1, 0, Hash::default());
let last_entry = entries.last().unwrap().clone();
let mut shreds =
entries_to_test_shreds(entries, slot, slot.saturating_sub(1), false);
entries_to_test_shreds(entries, slot, slot.saturating_sub(1), false, 0);
for b in shreds.iter_mut() {
b.set_index(index);
b.set_slot(slot as u64);
@ -2526,7 +2534,7 @@ pub mod tests {
for slot in 0..num_slots {
let entries = create_ticks(entries_per_slot, 0, Hash::default());
let shreds =
entries_to_test_shreds(entries.clone(), slot, slot.saturating_sub(1), false);
entries_to_test_shreds(entries.clone(), slot, slot.saturating_sub(1), false, 0);
assert!(shreds.len() as u64 >= shreds_per_slot);
blocktree
.insert_shreds(shreds, None, false)
@ -2621,7 +2629,7 @@ pub mod tests {
assert_eq!(blocktree.get_slot_entries(0, 0, None).unwrap(), vec![]);
let duplicate_shreds = entries_to_test_shreds(original_entries.clone(), 0, 0, true);
let duplicate_shreds = entries_to_test_shreds(original_entries.clone(), 0, 0, true, 0);
let num_shreds = duplicate_shreds.len() as u64;
blocktree
.insert_shreds(duplicate_shreds, None, false)
@ -3328,7 +3336,7 @@ pub mod tests {
// Create enough entries to ensure there are at least two shreds created
let num_entries = max_ticks_per_n_shreds(1) + 1;
let entries = create_ticks(num_entries, 0, Hash::default());
let mut shreds = entries_to_test_shreds(entries, slot, 0, true);
let mut shreds = entries_to_test_shreds(entries, slot, 0, true, 0);
let num_shreds = shreds.len();
assert!(num_shreds > 1);
for (i, s) in shreds.iter_mut().enumerate() {
@ -3415,7 +3423,9 @@ pub mod tests {
// Write entries
let gap: u64 = 10;
let shreds: Vec<_> = (0..64)
.map(|i| Shred::new_from_data(slot, (i * gap) as u32, 0, None, false, false, i as u8))
.map(|i| {
Shred::new_from_data(slot, (i * gap) as u32, 0, None, false, false, i as u8, 0)
})
.collect();
blocktree.insert_shreds(shreds, None, false).unwrap();
@ -3449,7 +3459,7 @@ pub mod tests {
assert_eq!(blocktree.find_missing_data_indexes(slot, 0, 1, 2, 0), empty);
let entries = create_ticks(100, 0, Hash::default());
let mut shreds = entries_to_test_shreds(entries, slot, 0, true);
let mut shreds = entries_to_test_shreds(entries, slot, 0, true, 0);
assert!(shreds.len() > 2);
shreds.drain(2..);
@ -3491,7 +3501,7 @@ pub mod tests {
// Write entries
let num_entries = 10;
let entries = create_ticks(num_entries, 0, Hash::default());
let shreds = entries_to_test_shreds(entries, slot, 0, true);
let shreds = entries_to_test_shreds(entries, slot, 0, true, 0);
let num_shreds = shreds.len();
blocktree.insert_shreds(shreds, None, false).unwrap();
@ -3605,7 +3615,7 @@ pub mod tests {
let last_root = RwLock::new(0);
let slot = 1;
let (mut shred, coding) = Shredder::new_coding_shred_header(slot, 11, 11, 11, 10);
let (mut shred, coding) = Shredder::new_coding_shred_header(slot, 11, 11, 11, 10, 0);
let coding_shred = Shred::new_empty_from_header(
shred.clone(),
DataShredHeader::default(),
@ -4008,7 +4018,7 @@ pub mod tests {
let num_ticks = 8;
let entries = create_ticks(num_ticks, 0, Hash::default());
let slot = 1;
let shreds = entries_to_test_shreds(entries, slot, 0, false);
let shreds = entries_to_test_shreds(entries, slot, 0, false, 0);
let next_shred_index = shreds.len();
blocktree
.insert_shreds(shreds, None, false)
@ -4027,6 +4037,7 @@ pub mod tests {
true,
true,
0,
0,
)];
// With the corruption, nothing should be returned, even though an

View File

@ -532,6 +532,7 @@ pub fn fill_blocktree_slot_with_ticks(
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.unwrap();
@ -587,6 +588,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.expect("Expected to write shredded entries to blocktree");
@ -627,6 +629,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.expect("Expected to write shredded entries to blocktree");
@ -678,6 +681,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.expect("Expected to write shredded entries to blocktree");
@ -740,6 +744,7 @@ pub mod tests {
false,
&Arc::new(Keypair::new()),
entries,
0,
)
.expect("Expected to write shredded entries to blocktree");
}
@ -1151,6 +1156,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.unwrap();
let opts = ProcessOptions {
@ -1261,6 +1267,7 @@ pub mod tests {
true,
&Arc::new(Keypair::new()),
entries,
0,
)
.unwrap();

View File

@ -25,7 +25,7 @@ use std::{sync::Arc, time::Instant};
/// The following constants are computed by hand, and hardcoded.
/// `test_shred_constants` ensures that the values are correct.
/// Constants are used over lazy_static for performance reasons.
pub const SIZE_OF_COMMON_SHRED_HEADER: usize = 77;
pub const SIZE_OF_COMMON_SHRED_HEADER: usize = 79;
pub const SIZE_OF_DATA_SHRED_HEADER: usize = 3;
pub const SIZE_OF_CODING_SHRED_HEADER: usize = 6;
pub const SIZE_OF_SIGNATURE: usize = 64;
@ -83,6 +83,7 @@ pub struct ShredCommonHeader {
pub shred_type: ShredType,
pub slot: Slot,
pub index: u32,
pub version: u16,
}
/// The data shred header has parent offset and flags
@ -142,15 +143,20 @@ impl Shred {
is_last_data: bool,
is_last_in_slot: bool,
reference_tick: u8,
version: u16,
) -> Self {
let mut payload = vec![0; PACKET_DATA_SIZE];
let mut common_header = ShredCommonHeader::default();
common_header.slot = slot;
common_header.index = index;
let common_header = ShredCommonHeader {
slot,
index,
version,
..ShredCommonHeader::default()
};
let mut data_header = DataShredHeader::default();
data_header.parent_offset = parent_offset;
data_header.flags = reference_tick.min(SHRED_TICK_REFERENCE_MASK);
let mut data_header = DataShredHeader {
parent_offset,
flags: reference_tick.min(SHRED_TICK_REFERENCE_MASK),
};
if is_last_data {
data_header.flags |= DATA_COMPLETE_SHRED
@ -281,6 +287,10 @@ impl Shred {
self.common_header.index
}
pub fn version(&self) -> u16 {
self.common_header.version
}
pub fn set_index(&mut self, index: u32) {
self.common_header.index = index;
Self::serialize_obj_into(
@ -363,12 +373,26 @@ impl Shred {
self.signature()
.verify(pubkey.as_ref(), &self.payload[SIZE_OF_SIGNATURE..])
}
pub fn version_from_hash(hash: &Hash) -> u16 {
let hash = hash.as_ref();
let mut accum = [0u8; 2];
hash.chunks(2).for_each(|seed| {
accum
.iter_mut()
.zip(seed)
.for_each(|(accum, seed)| *accum ^= *seed)
});
// convert accum into a u16
((accum[0] as u16) << 8) | accum[1] as u16
}
}
#[derive(Debug)]
pub struct Shredder {
slot: Slot,
parent_slot: Slot,
version: u16,
fec_rate: f32,
keypair: Arc<Keypair>,
pub signing_coding_time: u128,
@ -382,6 +406,7 @@ impl Shredder {
fec_rate: f32,
keypair: Arc<Keypair>,
reference_tick: u8,
version: u16,
) -> Result<Self> {
if fec_rate > 1.0 || fec_rate < 0.0 {
Err(ShredError::InvalidFecRate(fec_rate))
@ -395,6 +420,7 @@ impl Shredder {
keypair,
signing_coding_time: 0,
reference_tick,
version,
})
}
}
@ -441,6 +467,7 @@ impl Shredder {
is_last_data,
is_last_in_slot,
self.reference_tick,
self.version,
);
Shredder::sign_shred(&self.keypair, &mut shred);
@ -458,7 +485,12 @@ impl Shredder {
data_shreds
.par_chunks(MAX_DATA_SHREDS_PER_FEC_BLOCK as usize)
.flat_map(|shred_data_batch| {
Shredder::generate_coding_shreds(self.slot, self.fec_rate, shred_data_batch)
Shredder::generate_coding_shreds(
self.slot,
self.fec_rate,
shred_data_batch,
self.version,
)
})
.collect()
})
@ -503,11 +535,15 @@ impl Shredder {
num_data: usize,
num_code: usize,
position: usize,
version: u16,
) -> (ShredCommonHeader, CodingShredHeader) {
let mut header = ShredCommonHeader::default();
header.shred_type = ShredType(CODING_SHRED);
header.index = index;
header.slot = slot;
let header = ShredCommonHeader {
shred_type: ShredType(CODING_SHRED),
index,
slot,
version,
..ShredCommonHeader::default()
};
(
header,
CodingShredHeader {
@ -523,6 +559,7 @@ impl Shredder {
slot: Slot,
fec_rate: f32,
data_shred_batch: &[Shred],
version: u16,
) -> Vec<Shred> {
assert!(!data_shred_batch.is_empty());
if fec_rate != 0.0 {
@ -549,6 +586,7 @@ impl Shredder {
num_data,
num_coding,
i,
version,
);
let shred =
Shred::new_empty_from_header(header, DataShredHeader::default(), coding_header);
@ -578,6 +616,7 @@ impl Shredder {
num_data,
num_coding,
i,
version,
);
Shred {
common_header,
@ -781,6 +820,7 @@ pub mod tests {
use super::*;
use bincode::serialized_size;
use matches::assert_matches;
use solana_sdk::hash::hash;
use solana_sdk::system_transaction;
use std::collections::HashSet;
use std::convert::TryInto;
@ -848,7 +888,7 @@ pub mod tests {
// Test that parent cannot be > current slot
assert_matches!(
Shredder::new(slot, slot + 1, 1.00, keypair.clone(), 0),
Shredder::new(slot, slot + 1, 1.00, keypair.clone(), 0, 0),
Err(ShredError::SlotTooLow {
slot: _,
parent_slot: _,
@ -856,7 +896,7 @@ pub mod tests {
);
// Test that slot - parent cannot be > u16 MAX
assert_matches!(
Shredder::new(slot, slot - 1 - 0xffff, 1.00, keypair.clone(), 0),
Shredder::new(slot, slot - 1 - 0xffff, 1.00, keypair.clone(), 0, 0),
Err(ShredError::SlotTooLow {
slot: _,
parent_slot: _,
@ -865,7 +905,7 @@ pub mod tests {
let fec_rate = 0.25;
let parent_slot = slot - 5;
let shredder = Shredder::new(slot, parent_slot, fec_rate, keypair.clone(), 0)
let shredder = Shredder::new(slot, parent_slot, fec_rate, keypair.clone(), 0, 0)
.expect("Failed in creating shredder");
let entries: Vec<_> = (0..5)
@ -940,7 +980,7 @@ pub mod tests {
let slot = 1;
let parent_slot = 0;
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), 0)
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), 0, 0)
.expect("Failed in creating shredder");
let entries: Vec<_> = (0..5)
@ -966,7 +1006,7 @@ pub mod tests {
let slot = 1;
let parent_slot = 0;
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), 5)
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), 5, 0)
.expect("Failed in creating shredder");
let entries: Vec<_> = (0..5)
@ -996,7 +1036,7 @@ pub mod tests {
let slot = 1;
let parent_slot = 0;
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), u8::max_value())
let shredder = Shredder::new(slot, parent_slot, 0.0, keypair.clone(), u8::max_value(), 0)
.expect("Failed in creating shredder");
let entries: Vec<_> = (0..5)
@ -1033,11 +1073,11 @@ pub mod tests {
let slot = 0x123456789abcdef0;
// Test that FEC rate cannot be > 1.0
assert_matches!(
Shredder::new(slot, slot - 5, 1.001, keypair.clone(), 0),
Shredder::new(slot, slot - 5, 1.001, keypair.clone(), 0, 0),
Err(ShredError::InvalidFecRate(_))
);
let shredder = Shredder::new(0x123456789abcdef0, slot - 5, 1.0, keypair.clone(), 0)
let shredder = Shredder::new(0x123456789abcdef0, slot - 5, 1.0, keypair.clone(), 0, 0)
.expect("Failed in creating shredder");
// Create enough entries to make > 1 shred
@ -1079,7 +1119,7 @@ pub mod tests {
fn test_recovery_and_reassembly() {
let keypair = Arc::new(Keypair::new());
let slot = 0x123456789abcdef0;
let shredder = Shredder::new(slot, slot - 5, 1.0, keypair.clone(), 0)
let shredder = Shredder::new(slot, slot - 5, 1.0, keypair.clone(), 0, 0)
.expect("Failed in creating shredder");
let keypair0 = Keypair::new();
@ -1325,7 +1365,7 @@ pub mod tests {
fn test_multi_fec_block_coding() {
let keypair = Arc::new(Keypair::new());
let slot = 0x123456789abcdef0;
let shredder = Shredder::new(slot, slot - 5, 1.0, keypair.clone(), 0)
let shredder = Shredder::new(slot, slot - 5, 1.0, keypair.clone(), 0, 0)
.expect("Failed in creating shredder");
let num_fec_sets = 100;
@ -1408,4 +1448,54 @@ pub mod tests {
let result = Shredder::deshred(&all_shreds[..]).unwrap();
assert_eq!(serialized_entries[..], result[..serialized_entries.len()]);
}
#[test]
fn test_shred_version() {
let keypair = Arc::new(Keypair::new());
let hash = hash(Hash::default().as_ref());
let version = Shred::version_from_hash(&hash);
assert_ne!(version, 0);
let shredder =
Shredder::new(0, 0, 1.0, keypair, 0, version).expect("Failed in creating shredder");
let entries: Vec<_> = (0..5)
.map(|_| {
let keypair0 = Keypair::new();
let keypair1 = Keypair::new();
let tx0 =
system_transaction::transfer(&keypair0, &keypair1.pubkey(), 1, Hash::default());
Entry::new(&Hash::default(), 1, vec![tx0])
})
.collect();
let (data_shreds, coding_shreds, _next_index) =
shredder.entries_to_shreds(&entries, true, 0);
assert!(!data_shreds
.iter()
.chain(coding_shreds.iter())
.any(|s| s.version() != version));
}
#[test]
fn test_version_from_hash() {
let hash = [
0xa5u8, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5,
0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a,
0xa5, 0xa5, 0x5a, 0x5a,
];
let version = Shred::version_from_hash(&Hash::new(&hash));
assert_eq!(version, 0);
let hash = [
0xa5u8, 0xa5, 0x5a, 0x5a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
];
let version = Shred::version_from_hash(&Hash::new(&hash));
assert_eq!(version, 0xffff);
let hash = [
0xa5u8, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
let version = Shred::version_from_hash(&Hash::new(&hash));
assert_eq!(version, 0x5a5a);
}
}

View File

@ -486,7 +486,7 @@ pub mod tests {
let mut packet = Packet::default();
let slot = 0xdeadc0de;
let mut shred =
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0);
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0, 0);
assert_eq!(shred.slot(), slot);
let keypair = Keypair::new();
Shredder::sign_shred(&keypair, &mut shred);
@ -520,7 +520,7 @@ pub mod tests {
let mut batch = [Packets::default()];
let slot = 0xdeadc0de;
let mut shred =
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0);
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0, 0);
let keypair = Keypair::new();
Shredder::sign_shred(&keypair, &mut shred);
batch[0].packets.resize(1, Packet::default());
@ -563,7 +563,7 @@ pub mod tests {
let mut batch = [Packets::default()];
let slot = 0xdeadc0de;
let mut shred =
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0);
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0, 0);
let keypair = Keypair::new();
Shredder::sign_shred(&keypair, &mut shred);
batch[0].packets.resize(1, Packet::default());
@ -615,7 +615,8 @@ pub mod tests {
let mut batch = [Packets::default()];
let slot = 0xdeadc0de;
let keypair = Keypair::new();
let shred = Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0);
let shred =
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0, 0);
batch[0].packets.resize(1, Packet::default());
batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload);
batch[0].packets[0].meta.size = shred.payload.len();
@ -652,7 +653,8 @@ pub mod tests {
let mut batch = [Packets::default()];
let slot = 0xdeadc0de;
let keypair = Keypair::new();
let shred = Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0);
let shred =
Shred::new_from_data(slot, 0xc0de, 0xdead, Some(&[1, 2, 3, 4]), true, true, 0, 0);
batch[0].packets.resize(1, Packet::default());
batch[0].packets[0].data[0..shred.payload.len()].copy_from_slice(&shred.payload);
batch[0].packets[0].meta.size = shred.payload.len();

View File

@ -20,7 +20,7 @@ fn test_multiple_threads_insert_shred() {
let threads: Vec<_> = (0..num_threads)
.map(|i| {
let entries = entry::create_ticks(1, 0, Hash::default());
let shreds = blocktree::entries_to_test_shreds(entries, i + 1, 0, false);
let shreds = blocktree::entries_to_test_shreds(entries, i + 1, 0, false, 0);
let blocktree_ = blocktree.clone();
Builder::new()
.name("blocktree-writer".to_string())