Dynamic erasure set configuration (#5018)

* Use local erasure session to create/broadcast coding blobs

* Individual session for each recovery (as the config might be different)

* address review comments

* new constructors for session and coding generator

* unit test for dynamic erasure config
This commit is contained in:
Pankaj Garg 2019-07-11 13:58:33 -07:00 committed by GitHub
parent a191f3fd90
commit 4c90898f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 314 additions and 84 deletions

View File

@ -2,7 +2,7 @@
//! Proof of History ledger as well as iterative read, append write, and random //! Proof of History ledger as well as iterative read, append write, and random
//! access read to a persistent file-based ledger. //! access read to a persistent file-based ledger.
use crate::entry::Entry; use crate::entry::Entry;
use crate::erasure::{self, Session}; use crate::erasure::{ErasureConfig, Session};
use crate::packet::{Blob, SharedBlob, BLOB_HEADER_SIZE}; use crate::packet::{Blob, SharedBlob, BLOB_HEADER_SIZE};
use crate::result::{Error, Result}; use crate::result::{Error, Result};
@ -90,7 +90,6 @@ pub struct Blocktree {
orphans_cf: LedgerColumn<cf::Orphans>, orphans_cf: LedgerColumn<cf::Orphans>,
index_cf: LedgerColumn<cf::Index>, index_cf: LedgerColumn<cf::Index>,
batch_processor: Arc<RwLock<BatchProcessor>>, batch_processor: Arc<RwLock<BatchProcessor>>,
session: Arc<erasure::Session>,
pub new_blobs_signals: Vec<SyncSender<bool>>, pub new_blobs_signals: Vec<SyncSender<bool>>,
pub completed_slots_senders: Vec<SyncSender<Vec<u64>>>, pub completed_slots_senders: Vec<SyncSender<Vec<u64>>>,
} }
@ -144,9 +143,6 @@ impl Blocktree {
let orphans_cf = db.column(); let orphans_cf = db.column();
let index_cf = db.column(); let index_cf = db.column();
// setup erasure
let session = Arc::new(erasure::Session::default());
let db = Arc::new(db); let db = Arc::new(db);
Ok(Blocktree { Ok(Blocktree {
@ -158,7 +154,6 @@ impl Blocktree {
erasure_meta_cf, erasure_meta_cf,
orphans_cf, orphans_cf,
index_cf, index_cf,
session,
new_blobs_signals: vec![], new_blobs_signals: vec![],
batch_processor, batch_processor,
completed_slots_senders: vec![], completed_slots_senders: vec![],
@ -328,11 +323,22 @@ impl Blocktree {
let mut slot_meta_working_set = HashMap::new(); let mut slot_meta_working_set = HashMap::new();
let mut erasure_meta_working_set = HashMap::new(); let mut erasure_meta_working_set = HashMap::new();
let mut index_working_set = HashMap::new(); let mut index_working_set = HashMap::new();
let mut erasure_config_opt = None;
for blob in new_blobs.iter() { for blob in new_blobs.iter() {
let blob = blob.borrow(); let blob = blob.borrow();
assert!(!blob.is_coding()); assert!(!blob.is_coding());
match erasure_config_opt {
Some(config) => {
if config != blob.erasure_config() {
// ToDo: This is a potential slashing condition
error!("Multiple erasure config for the same slot.");
}
}
None => erasure_config_opt = Some(blob.erasure_config()),
}
let blob_slot = blob.slot(); let blob_slot = blob.slot();
let _ = index_working_set.entry(blob_slot).or_insert_with(|| { let _ = index_working_set.entry(blob_slot).or_insert_with(|| {
@ -342,7 +348,8 @@ impl Blocktree {
.unwrap_or_else(|| Index::new(blob_slot)) .unwrap_or_else(|| Index::new(blob_slot))
}); });
let set_index = ErasureMeta::set_index_for(blob.index()); let set_index =
ErasureMeta::set_index_for(blob.index(), erasure_config_opt.unwrap().num_data());
if let Some(erasure_meta) = self.erasure_meta_cf.get((blob_slot, set_index))? { if let Some(erasure_meta) = self.erasure_meta_cf.get((blob_slot, set_index))? {
erasure_meta_working_set.insert((blob_slot, set_index), erasure_meta); erasure_meta_working_set.insert((blob_slot, set_index), erasure_meta);
} }
@ -350,12 +357,12 @@ impl Blocktree {
let recovered_data_opt = handle_recovery( let recovered_data_opt = handle_recovery(
&self.db, &self.db,
&self.session,
&erasure_meta_working_set, &erasure_meta_working_set,
&mut index_working_set, &mut index_working_set,
&prev_inserted_blob_datas, &prev_inserted_blob_datas,
&mut prev_inserted_coding, &mut prev_inserted_coding,
&mut write_batch, &mut write_batch,
&erasure_config_opt.unwrap_or_default(),
)?; )?;
if let Some(recovered_data) = recovered_data_opt { if let Some(recovered_data) = recovered_data_opt {
@ -540,13 +547,25 @@ impl Blocktree {
let mut prev_inserted_coding = HashMap::new(); let mut prev_inserted_coding = HashMap::new();
let mut prev_inserted_blob_datas = HashMap::new(); let mut prev_inserted_blob_datas = HashMap::new();
let mut erasure_config_opt = None;
for blob_item in blobs { for blob_item in blobs {
let blob = blob_item.borrow(); let blob = blob_item.borrow();
assert!(blob.is_coding()); assert!(blob.is_coding());
match erasure_config_opt {
Some(config) => {
if config != blob.erasure_config() {
// ToDo: This is a potential slashing condition
error!("Multiple erasure config for the same slot.");
}
}
None => erasure_config_opt = Some(blob.erasure_config()),
}
let (blob_slot, blob_index, blob_size) = let (blob_slot, blob_index, blob_size) =
(blob.slot(), blob.index(), blob.size() as usize); (blob.slot(), blob.index(), blob.size() as usize);
let set_index = blob_index / crate::erasure::NUM_CODING as u64; let set_index = blob_index / blob.erasure_config().num_coding() as u64;
writebatch.put_bytes::<cf::Coding>( writebatch.put_bytes::<cf::Coding>(
(blob_slot, blob_index), (blob_slot, blob_index),
@ -566,7 +585,9 @@ impl Blocktree {
self.erasure_meta_cf self.erasure_meta_cf
.get((blob_slot, set_index)) .get((blob_slot, set_index))
.expect("Expect database get to succeed") .expect("Expect database get to succeed")
.unwrap_or_else(|| ErasureMeta::new(set_index)) .unwrap_or_else(|| {
ErasureMeta::new(set_index, &erasure_config_opt.unwrap())
})
}); });
// size should be the same for all coding blobs, else there's a bug // size should be the same for all coding blobs, else there's a bug
@ -581,12 +602,12 @@ impl Blocktree {
let recovered_data_opt = handle_recovery( let recovered_data_opt = handle_recovery(
&self.db, &self.db,
&self.session,
&erasure_metas, &erasure_metas,
&mut index_working_set, &mut index_working_set,
&prev_inserted_blob_datas, &prev_inserted_blob_datas,
&mut prev_inserted_coding, &mut prev_inserted_coding,
&mut writebatch, &mut writebatch,
&erasure_config_opt.unwrap_or_default(),
)?; )?;
if let Some(recovered_data) = recovered_data_opt { if let Some(recovered_data) = recovered_data_opt {
@ -1475,12 +1496,12 @@ fn is_newly_completed_slot(slot_meta: &SlotMeta, backup_slot_meta: &Option<SlotM
fn handle_recovery( fn handle_recovery(
db: &Database, db: &Database,
session: &Session,
erasure_metas: &HashMap<(u64, u64), ErasureMeta>, erasure_metas: &HashMap<(u64, u64), ErasureMeta>,
index_working_set: &mut HashMap<u64, Index>, index_working_set: &mut HashMap<u64, Index>,
prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>, prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>,
prev_inserted_coding: &mut HashMap<(u64, u64), Blob>, prev_inserted_coding: &mut HashMap<(u64, u64), Blob>,
writebatch: &mut WriteBatch, writebatch: &mut WriteBatch,
erasure_config: &ErasureConfig,
) -> Result<Option<Vec<Blob>>> { ) -> Result<Option<Vec<Blob>>> {
use solana_sdk::signature::Signable; use solana_sdk::signature::Signable;
@ -1491,12 +1512,12 @@ fn handle_recovery(
if let Some((mut data, coding)) = try_erasure_recover( if let Some((mut data, coding)) = try_erasure_recover(
db, db,
session,
&erasure_meta, &erasure_meta,
index, index,
slot, slot,
&prev_inserted_blob_datas, &prev_inserted_blob_datas,
&prev_inserted_coding, &prev_inserted_coding,
erasure_config,
)? { )? {
for blob in data.iter() { for blob in data.iter() {
debug!( debug!(
@ -1587,15 +1608,13 @@ fn handle_recovery(
/// Attempts recovery using erasure coding /// Attempts recovery using erasure coding
fn try_erasure_recover( fn try_erasure_recover(
db: &Database, db: &Database,
session: &Session,
erasure_meta: &ErasureMeta, erasure_meta: &ErasureMeta,
index: &Index, index: &Index,
slot: u64, slot: u64,
prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>, prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>,
prev_inserted_coding: &HashMap<(u64, u64), Blob>, prev_inserted_coding: &HashMap<(u64, u64), Blob>,
erasure_config: &ErasureConfig,
) -> Result<Option<(Vec<Blob>, Vec<Blob>)>> { ) -> Result<Option<(Vec<Blob>, Vec<Blob>)>> {
use crate::erasure::ERASURE_SET_SIZE;
let set_index = erasure_meta.set_index; let set_index = erasure_meta.set_index;
let start_index = erasure_meta.start_index(); let start_index = erasure_meta.start_index();
let (data_end_index, coding_end_idx) = erasure_meta.end_indexes(); let (data_end_index, coding_end_idx) = erasure_meta.end_indexes();
@ -1613,14 +1632,16 @@ fn try_erasure_recover(
let blobs = match erasure_meta.status(index) { let blobs = match erasure_meta.status(index) {
ErasureMetaStatus::CanRecover => { ErasureMetaStatus::CanRecover => {
let session = Session::new_from_config(erasure_config).unwrap();
let erasure_result = recover( let erasure_result = recover(
db, db,
session, &session,
slot, slot,
erasure_meta, erasure_meta,
index, index,
prev_inserted_blob_datas, prev_inserted_blob_datas,
prev_inserted_coding, prev_inserted_coding,
erasure_config,
); );
match erasure_result { match erasure_result {
@ -1628,7 +1649,7 @@ fn try_erasure_recover(
let recovered = data.len() + coding.len(); let recovered = data.len() + coding.len();
assert_eq!( assert_eq!(
ERASURE_SET_SIZE, erasure_config.num_data() + erasure_config.num_coding(),
recovered recovered
+ index.data().present_in_bounds(start_index..data_end_index) + index.data().present_in_bounds(start_index..data_end_index)
+ index + index
@ -1694,9 +1715,8 @@ fn recover(
index: &Index, index: &Index,
prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>, prev_inserted_blob_datas: &HashMap<(u64, u64), &[u8]>,
prev_inserted_coding: &HashMap<(u64, u64), Blob>, prev_inserted_coding: &HashMap<(u64, u64), Blob>,
erasure_config: &ErasureConfig,
) -> Result<(Vec<Blob>, Vec<Blob>)> { ) -> Result<(Vec<Blob>, Vec<Blob>)> {
use crate::erasure::{ERASURE_SET_SIZE, NUM_DATA};
let start_idx = erasure_meta.start_index(); let start_idx = erasure_meta.start_index();
let size = erasure_meta.size(); let size = erasure_meta.size();
let data_cf = db.column::<cf::Data>(); let data_cf = db.column::<cf::Data>();
@ -1709,8 +1729,9 @@ fn recover(
let (data_end_idx, coding_end_idx) = erasure_meta.end_indexes(); let (data_end_idx, coding_end_idx) = erasure_meta.end_indexes();
let present = &mut [true; ERASURE_SET_SIZE]; let erasure_set_size = erasure_config.num_data() + erasure_config.num_coding();
let mut blobs = Vec::with_capacity(ERASURE_SET_SIZE); let present = &mut vec![true; erasure_set_size];
let mut blobs = Vec::with_capacity(erasure_set_size);
for i in start_idx..data_end_idx { for i in start_idx..data_end_idx {
if index.data().is_present(i) { if index.data().is_present(i) {
@ -1753,7 +1774,7 @@ fn recover(
blobs.push(blob.data[BLOB_HEADER_SIZE..BLOB_HEADER_SIZE + size].to_vec()); blobs.push(blob.data[BLOB_HEADER_SIZE..BLOB_HEADER_SIZE + size].to_vec());
} else { } else {
trace!("[recover] absent coding blob at {}", i); trace!("[recover] absent coding blob at {}", i);
let set_relative_idx = (i - start_idx) as usize + NUM_DATA; let set_relative_idx = (i - start_idx) as usize + erasure_config.num_data();
blobs.push(vec![0; size]); blobs.push(vec![0; size]);
present[set_relative_idx] = false; present[set_relative_idx] = false;
} }
@ -1919,7 +1940,7 @@ pub mod tests {
use crate::entry::{ use crate::entry::{
create_ticks, make_tiny_test_entries, make_tiny_test_entries_from_hash, Entry, EntrySlice, create_ticks, make_tiny_test_entries, make_tiny_test_entries_from_hash, Entry, EntrySlice,
}; };
use crate::erasure::{CodingGenerator, NUM_CODING, NUM_DATA}; use crate::erasure::{CodingGenerator, ErasureConfig};
use crate::packet; use crate::packet;
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use rand::thread_rng; use rand::thread_rng;
@ -2908,7 +2929,8 @@ pub mod tests {
let branching_factor: u64 = 4; let branching_factor: u64 = 4;
// Number of slots that will be in the tree // Number of slots that will be in the tree
let num_slots = (branching_factor.pow(num_tree_levels) - 1) / (branching_factor - 1); let num_slots = (branching_factor.pow(num_tree_levels) - 1) / (branching_factor - 1);
let entries_per_slot = NUM_DATA as u64; let erasure_config = ErasureConfig::default();
let entries_per_slot = erasure_config.num_data() as u64;
assert!(entries_per_slot > 1); assert!(entries_per_slot > 1);
let (mut blobs, _) = make_many_slot_entries(0, num_slots, entries_per_slot); let (mut blobs, _) = make_many_slot_entries(0, num_slots, entries_per_slot);
@ -2939,9 +2961,9 @@ pub mod tests {
.cloned() .cloned()
.map(|blob| Arc::new(RwLock::new(blob))) .map(|blob| Arc::new(RwLock::new(blob)))
.collect(); .collect();
let mut coding_generator = CodingGenerator::new(Arc::clone(&blocktree.session)); let mut coding_generator = CodingGenerator::new_from_config(&erasure_config);
let coding_blobs = coding_generator.next(&shared_blobs); let coding_blobs = coding_generator.next(&shared_blobs);
assert_eq!(coding_blobs.len(), NUM_CODING); assert_eq!(coding_blobs.len(), erasure_config.num_coding());
let mut rng = thread_rng(); let mut rng = thread_rng();
@ -3437,7 +3459,7 @@ pub mod tests {
use super::*; use super::*;
use crate::blocktree::meta::ErasureMetaStatus; use crate::blocktree::meta::ErasureMetaStatus;
use crate::erasure::test::{generate_ledger_model, ErasureSpec, SlotSpec}; use crate::erasure::test::{generate_ledger_model, ErasureSpec, SlotSpec};
use crate::erasure::{CodingGenerator, NUM_CODING, NUM_DATA}; use crate::erasure::CodingGenerator;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use solana_sdk::signature::Signable; use solana_sdk::signature::Signable;
use std::sync::RwLock; use std::sync::RwLock;
@ -3457,8 +3479,9 @@ pub mod tests {
let path = get_tmp_ledger_path!(); let path = get_tmp_ledger_path!();
let blocktree = Blocktree::open(&path).unwrap(); let blocktree = Blocktree::open(&path).unwrap();
let erasure_config = ErasureConfig::default();
// two erasure sets // two erasure sets
let num_blobs = NUM_DATA as u64 * 2; let num_blobs = erasure_config.num_data() as u64 * 2;
let slot = 0; let slot = 0;
let (mut blobs, _) = make_slot_entries(slot, 0, num_blobs); let (mut blobs, _) = make_slot_entries(slot, 0, num_blobs);
@ -3481,11 +3504,13 @@ pub mod tests {
assert!(erasure_meta_opt.is_none()); assert!(erasure_meta_opt.is_none());
blocktree.write_blobs(&blobs[2..NUM_DATA]).unwrap(); blocktree
.write_blobs(&blobs[2..erasure_config.num_data()])
.unwrap();
// insert all coding blobs in first set // insert all coding blobs in first set
let mut coding_generator = CodingGenerator::new(Arc::clone(&blocktree.session)); let mut coding_generator = CodingGenerator::new_from_config(&erasure_config);
let coding_blobs = coding_generator.next(&shared_blobs[..NUM_DATA]); let coding_blobs = coding_generator.next(&shared_blobs[..erasure_config.num_data()]);
blocktree blocktree
.put_shared_coding_blobs(coding_blobs.iter()) .put_shared_coding_blobs(coding_blobs.iter())
@ -3500,11 +3525,11 @@ pub mod tests {
assert_eq!(erasure_meta.status(&index), DataFull); assert_eq!(erasure_meta.status(&index), DataFull);
// insert blob in the 2nd set so that recovery should be possible given all coding blobs // insert blob in the 2nd set so that recovery should be possible given all coding blobs
let set2 = &blobs[NUM_DATA..]; let set2 = &blobs[erasure_config.num_data()..];
blocktree.write_blobs(&set2[..1]).unwrap(); blocktree.write_blobs(&set2[..1]).unwrap();
// insert all coding blobs in 2nd set. Should trigger recovery // insert all coding blobs in 2nd set. Should trigger recovery
let coding_blobs = coding_generator.next(&shared_blobs[NUM_DATA..]); let coding_blobs = coding_generator.next(&shared_blobs[erasure_config.num_data()..]);
blocktree blocktree
.put_shared_coding_blobs(coding_blobs.iter()) .put_shared_coding_blobs(coding_blobs.iter())
@ -3542,10 +3567,12 @@ pub mod tests {
let slot = 0; let slot = 0;
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
let erasure_config = ErasureConfig::default();
let blocktree = Blocktree::open(&ledger_path).unwrap(); let blocktree = Blocktree::open(&ledger_path).unwrap();
let num_sets = 3; let num_sets = 3;
let data_blobs = make_slot_entries(slot, 0, num_sets * NUM_DATA as u64) let data_blobs =
make_slot_entries(slot, 0, num_sets * erasure_config.num_data() as u64)
.0 .0
.into_iter() .into_iter()
.map(Blob::into) .map(Blob::into)
@ -3557,12 +3584,15 @@ pub mod tests {
b.sign(&keypair); b.sign(&keypair);
}); });
let mut coding_generator = CodingGenerator::new(Arc::clone(&blocktree.session)); let mut coding_generator = CodingGenerator::new_from_config(&erasure_config);
for (set_index, data_blobs) in data_blobs.chunks_exact(NUM_DATA).enumerate() { for (set_index, data_blobs) in data_blobs
.chunks_exact(erasure_config.num_data())
.enumerate()
{
let coding_blobs = coding_generator.next(&data_blobs); let coding_blobs = coding_generator.next(&data_blobs);
assert_eq!(coding_blobs.len(), NUM_CODING); assert_eq!(coding_blobs.len(), erasure_config.num_coding());
let deleted_data = data_blobs[0].clone(); let deleted_data = data_blobs[0].clone();
@ -3577,15 +3607,21 @@ pub mod tests {
// Verify the slot meta // Verify the slot meta
let slot_meta = blocktree.meta(slot).unwrap().unwrap(); let slot_meta = blocktree.meta(slot).unwrap().unwrap();
assert_eq!(slot_meta.consumed, (NUM_DATA * (set_index + 1)) as u64); assert_eq!(
assert_eq!(slot_meta.received, (NUM_DATA * (set_index + 1)) as u64); slot_meta.consumed,
(erasure_config.num_data() * (set_index + 1)) as u64
);
assert_eq!(
slot_meta.received,
(erasure_config.num_data() * (set_index + 1)) as u64
);
assert_eq!(slot_meta.parent_slot, 0); assert_eq!(slot_meta.parent_slot, 0);
assert!(slot_meta.next_slots.is_empty()); assert!(slot_meta.next_slots.is_empty());
assert_eq!(slot_meta.is_connected, true); assert_eq!(slot_meta.is_connected, true);
if set_index as u64 == num_sets - 1 { if set_index as u64 == num_sets - 1 {
assert_eq!( assert_eq!(
slot_meta.last_index, slot_meta.last_index,
(NUM_DATA * (set_index + 1) - 1) as u64 (erasure_config.num_data() * (set_index + 1) - 1) as u64
); );
} }
@ -3628,22 +3664,25 @@ pub mod tests {
solana_logger::setup(); solana_logger::setup();
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
let erasure_config = ErasureConfig::default();
let blocktree = Blocktree::open(&ledger_path).unwrap(); let blocktree = Blocktree::open(&ledger_path).unwrap();
let data_blobs = make_slot_entries(SLOT, 0, NUM_DATA as u64) let data_blobs = make_slot_entries(SLOT, 0, erasure_config.num_data() as u64)
.0 .0
.into_iter() .into_iter()
.map(Blob::into) .map(Blob::into)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut coding_generator = CodingGenerator::new(Arc::clone(&blocktree.session)); let session = Arc::new(Session::new_from_config(&erasure_config).unwrap());
let mut coding_generator = CodingGenerator::new(Arc::clone(&session));
let shared_coding_blobs = coding_generator.next(&data_blobs); let shared_coding_blobs = coding_generator.next(&data_blobs);
assert_eq!(shared_coding_blobs.len(), NUM_CODING); assert_eq!(shared_coding_blobs.len(), erasure_config.num_coding());
let mut prev_coding = HashMap::new(); let mut prev_coding = HashMap::new();
let prev_data = HashMap::new(); let prev_data = HashMap::new();
let mut index = Index::new(SLOT); let mut index = Index::new(SLOT);
let mut erasure_meta = ErasureMeta::new(SET_INDEX); let mut erasure_meta = ErasureMeta::new(SET_INDEX, &erasure_config);
erasure_meta.size = shared_coding_blobs[0].read().unwrap().size(); erasure_meta.size = shared_coding_blobs[0].read().unwrap().size();
for shared_blob in shared_coding_blobs.iter() { for shared_blob in shared_coding_blobs.iter() {
@ -3652,18 +3691,19 @@ pub mod tests {
prev_coding.insert((blob.slot(), blob.index()), blob.clone()); prev_coding.insert((blob.slot(), blob.index()), blob.clone());
} }
index index.coding_mut().set_many_present(
.coding_mut() (0..erasure_config.num_coding() as u64).zip(std::iter::repeat(true)),
.set_many_present((0..NUM_CODING as u64).zip(std::iter::repeat(true))); );
let (recovered_data, recovered_coding) = recover( let (recovered_data, recovered_coding) = recover(
&blocktree.db, &blocktree.db,
&blocktree.session, &session,
SLOT, SLOT,
&erasure_meta, &erasure_meta,
&index, &index,
&prev_data, &prev_data,
&prev_coding, &prev_coding,
&erasure_config,
) )
.expect("Successful recovery"); .expect("Successful recovery");
@ -3688,6 +3728,71 @@ pub mod tests {
} }
} }
pub fn try_recovery_using_erasure_config(
erasure_config: &ErasureConfig,
num_drop_data: usize,
slot: u64,
blocktree: &Blocktree,
) -> ErasureMetaStatus {
let entries = make_tiny_test_entries(erasure_config.num_data());
let mut blobs = entries_to_blobs_using_config(&entries, slot, 0, true, &erasure_config);
let keypair = Keypair::new();
blobs.iter_mut().for_each(|blob| {
blob.set_id(&keypair.pubkey());
blob.sign(&keypair);
});
let shared_blobs: Vec<_> = blobs
.iter()
.cloned()
.map(|blob| Arc::new(RwLock::new(blob)))
.collect();
blocktree
.write_blobs(&blobs[..(erasure_config.num_data() - num_drop_data)])
.unwrap();
let mut coding_generator = CodingGenerator::new_from_config(&erasure_config);
let coding_blobs = coding_generator.next(&shared_blobs[..erasure_config.num_data()]);
blocktree
.put_shared_coding_blobs(coding_blobs.iter())
.unwrap();
let erasure_meta = blocktree
.erasure_meta(slot, 0)
.expect("DB get must succeed")
.unwrap();
let index = blocktree.get_index(slot).unwrap().unwrap();
erasure_meta.status(&index)
}
#[test]
fn test_recovery_different_configs() {
use ErasureMetaStatus::DataFull;
solana_logger::setup();
let ledger_path = get_tmp_ledger_path!();
let blocktree = Blocktree::open(&ledger_path).unwrap();
assert_eq!(
try_recovery_using_erasure_config(&ErasureConfig::default(), 4, 0, &blocktree),
DataFull
);
assert_eq!(
try_recovery_using_erasure_config(&ErasureConfig::new(12, 8), 8, 1, &blocktree),
DataFull
);
assert_eq!(
try_recovery_using_erasure_config(&ErasureConfig::new(16, 4), 4, 2, &blocktree),
DataFull
);
}
#[test] #[test]
fn test_recovery_fails_safely() { fn test_recovery_fails_safely() {
const SLOT: u64 = 0; const SLOT: u64 = 0;
@ -3695,17 +3800,18 @@ pub mod tests {
solana_logger::setup(); solana_logger::setup();
let ledger_path = get_tmp_ledger_path!(); let ledger_path = get_tmp_ledger_path!();
let erasure_config = ErasureConfig::default();
let blocktree = Blocktree::open(&ledger_path).unwrap(); let blocktree = Blocktree::open(&ledger_path).unwrap();
let data_blobs = make_slot_entries(SLOT, 0, NUM_DATA as u64) let data_blobs = make_slot_entries(SLOT, 0, erasure_config.num_data() as u64)
.0 .0
.into_iter() .into_iter()
.map(Blob::into) .map(Blob::into)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut coding_generator = CodingGenerator::new(Arc::clone(&blocktree.session)); let mut coding_generator = CodingGenerator::new_from_config(&erasure_config);
let shared_coding_blobs = coding_generator.next(&data_blobs); let shared_coding_blobs = coding_generator.next(&data_blobs);
assert_eq!(shared_coding_blobs.len(), NUM_CODING); assert_eq!(shared_coding_blobs.len(), erasure_config.num_coding());
// Insert coding blobs except 1 and no data. Not enough to do recovery // Insert coding blobs except 1 and no data. Not enough to do recovery
blocktree blocktree
@ -3728,12 +3834,12 @@ pub mod tests {
let attempt_result = try_erasure_recover( let attempt_result = try_erasure_recover(
&blocktree.db, &blocktree.db,
&blocktree.session,
&erasure_meta, &erasure_meta,
&index, &index,
SLOT, SLOT,
&prev_inserted_blob_datas, &prev_inserted_blob_datas,
&prev_inserted_coding, &prev_inserted_coding,
&erasure_config,
); );
assert!(attempt_result.is_ok()); assert!(attempt_result.is_ok());
@ -3770,7 +3876,9 @@ pub mod tests {
let max_erasure_sets = 16; let max_erasure_sets = 16;
solana_logger::setup(); solana_logger::setup();
let erasure_config = ErasureConfig::default();
let path = get_tmp_ledger_path!(); let path = get_tmp_ledger_path!();
let blocktree = Arc::new(Blocktree::open(&path).unwrap());
let mut rng = thread_rng(); let mut rng = thread_rng();
// Specification should generate a ledger where each slot has an random number of // Specification should generate a ledger where each slot has an random number of
@ -3786,11 +3894,14 @@ pub mod tests {
.map(|set_index| { .map(|set_index| {
let (num_data, num_coding) = if set_index % 2 == 0 { let (num_data, num_coding) = if set_index % 2 == 0 {
( (
NUM_DATA - rng.gen_range(1, 3), erasure_config.num_data() - rng.gen_range(1, 3),
NUM_CODING - rng.gen_range(1, 3), erasure_config.num_coding() - rng.gen_range(1, 3),
) )
} else { } else {
(NUM_DATA - rng.gen_range(1, 5), NUM_CODING) (
erasure_config.num_data() - rng.gen_range(1, 5),
erasure_config.num_coding(),
)
}; };
ErasureSpec { ErasureSpec {
set_index, set_index,
@ -3805,7 +3916,6 @@ pub mod tests {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let model = generate_ledger_model(specs); let model = generate_ledger_model(specs);
let blocktree = Arc::new(Blocktree::open(&path).unwrap());
// Write to each slot in a different thread simultaneously. // Write to each slot in a different thread simultaneously.
// These writes should trigger the recovery. Every erasure set should have all of its // These writes should trigger the recovery. Every erasure set should have all of its
@ -3954,7 +4064,7 @@ pub mod tests {
// Should have all data // Should have all data
assert_eq!( assert_eq!(
index.data().present_in_bounds(start_index..data_end_idx), index.data().present_in_bounds(start_index..data_end_idx),
NUM_DATA erasure_config.num_data()
); );
} }
} }
@ -3964,17 +4074,19 @@ pub mod tests {
} }
} }
pub fn entries_to_blobs( pub fn entries_to_blobs_using_config(
entries: &Vec<Entry>, entries: &Vec<Entry>,
slot: u64, slot: u64,
parent_slot: u64, parent_slot: u64,
is_full_slot: bool, is_full_slot: bool,
config: &ErasureConfig,
) -> Vec<Blob> { ) -> Vec<Blob> {
let mut blobs = entries.clone().to_single_entry_blobs(); let mut blobs = entries.clone().to_single_entry_blobs();
for (i, b) in blobs.iter_mut().enumerate() { for (i, b) in blobs.iter_mut().enumerate() {
b.set_index(i as u64); b.set_index(i as u64);
b.set_slot(slot); b.set_slot(slot);
b.set_parent(parent_slot); b.set_parent(parent_slot);
b.set_erasure_config(config);
} }
if is_full_slot { if is_full_slot {
blobs.last_mut().unwrap().set_is_last_in_slot(); blobs.last_mut().unwrap().set_is_last_in_slot();
@ -3982,6 +4094,21 @@ pub mod tests {
blobs blobs
} }
pub fn entries_to_blobs(
entries: &Vec<Entry>,
slot: u64,
parent_slot: u64,
is_full_slot: bool,
) -> Vec<Blob> {
entries_to_blobs_using_config(
entries,
slot,
parent_slot,
is_full_slot,
&ErasureConfig::default(),
)
}
pub fn make_slot_entries( pub fn make_slot_entries(
slot: u64, slot: u64,
parent_slot: u64, parent_slot: u64,

View File

@ -1,4 +1,4 @@
use crate::erasure::{NUM_CODING, NUM_DATA}; use crate::erasure::ErasureConfig;
use solana_metrics::datapoint; use solana_metrics::datapoint;
use std::{collections::BTreeSet, ops::RangeBounds}; use std::{collections::BTreeSet, ops::RangeBounds};
@ -55,6 +55,8 @@ pub struct ErasureMeta {
pub set_index: u64, pub set_index: u64,
/// Size of shards in this erasure set /// Size of shards in this erasure set
pub size: usize, pub size: usize,
/// Erasure configuration for this erasure set
config: ErasureConfig,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -183,8 +185,12 @@ impl SlotMeta {
} }
impl ErasureMeta { impl ErasureMeta {
pub fn new(set_index: u64) -> ErasureMeta { pub fn new(set_index: u64, config: &ErasureConfig) -> ErasureMeta {
ErasureMeta { set_index, size: 0 } ErasureMeta {
set_index,
size: 0,
config: *config,
}
} }
pub fn status(&self, index: &Index) -> ErasureMetaStatus { pub fn status(&self, index: &Index) -> ErasureMetaStatus {
@ -196,16 +202,19 @@ impl ErasureMeta {
let num_coding = index.coding().present_in_bounds(start_idx..coding_end_idx); let num_coding = index.coding().present_in_bounds(start_idx..coding_end_idx);
let num_data = index.data().present_in_bounds(start_idx..data_end_idx); let num_data = index.data().present_in_bounds(start_idx..data_end_idx);
let (data_missing, coding_missing) = (NUM_DATA - num_data, NUM_CODING - num_coding); let (data_missing, coding_missing) = (
self.config.num_data() - num_data,
self.config.num_coding() - num_coding,
);
let total_missing = data_missing + coding_missing; let total_missing = data_missing + coding_missing;
if data_missing > 0 && total_missing <= NUM_CODING { if data_missing > 0 && total_missing <= self.config.num_coding() {
CanRecover CanRecover
} else if data_missing == 0 { } else if data_missing == 0 {
DataFull DataFull
} else { } else {
StillNeed(total_missing - NUM_CODING) StillNeed(total_missing - self.config.num_coding())
} }
} }
@ -217,18 +226,21 @@ impl ErasureMeta {
self.size self.size
} }
pub fn set_index_for(index: u64) -> u64 { pub fn set_index_for(index: u64, num_data: usize) -> u64 {
index / NUM_DATA as u64 index / num_data as u64
} }
pub fn start_index(&self) -> u64 { pub fn start_index(&self) -> u64 {
self.set_index * NUM_DATA as u64 self.set_index * self.config.num_data() as u64
} }
/// returns a tuple of (data_end, coding_end) /// returns a tuple of (data_end, coding_end)
pub fn end_indexes(&self) -> (u64, u64) { pub fn end_indexes(&self) -> (u64, u64) {
let start = self.start_index(); let start = self.start_index();
(start + NUM_DATA as u64, start + NUM_CODING as u64) (
start + self.config.num_data() as u64,
start + self.config.num_coding() as u64,
)
} }
} }
@ -243,16 +255,17 @@ mod test {
use ErasureMetaStatus::*; use ErasureMetaStatus::*;
let set_index = 0; let set_index = 0;
let erasure_config = ErasureConfig::default();
let mut e_meta = ErasureMeta::new(set_index); let mut e_meta = ErasureMeta::new(set_index, &erasure_config);
let mut rng = thread_rng(); let mut rng = thread_rng();
let mut index = Index::new(0); let mut index = Index::new(0);
e_meta.size = 1; e_meta.size = 1;
let data_indexes = 0..NUM_DATA as u64; let data_indexes = 0..erasure_config.num_data() as u64;
let coding_indexes = 0..NUM_CODING as u64; let coding_indexes = 0..erasure_config.num_coding() as u64;
assert_eq!(e_meta.status(&index), StillNeed(NUM_DATA)); assert_eq!(e_meta.status(&index), StillNeed(erasure_config.num_data()));
index index
.data_mut() .data_mut()
@ -267,7 +280,7 @@ mod test {
for &idx in data_indexes for &idx in data_indexes
.clone() .clone()
.collect::<Vec<_>>() .collect::<Vec<_>>()
.choose_multiple(&mut rng, NUM_DATA) .choose_multiple(&mut rng, erasure_config.num_data())
{ {
index.data_mut().set_present(idx, false); index.data_mut().set_present(idx, false);
@ -280,7 +293,7 @@ mod test {
for &idx in coding_indexes for &idx in coding_indexes
.collect::<Vec<_>>() .collect::<Vec<_>>()
.choose_multiple(&mut rng, NUM_CODING) .choose_multiple(&mut rng, erasure_config.num_coding())
{ {
index.coding_mut().set_present(idx, false); index.coding_mut().set_present(idx, false);

View File

@ -5,7 +5,7 @@ use self::fail_entry_verification_broadcast_run::FailEntryVerificationBroadcastR
use self::standard_broadcast_run::StandardBroadcastRun; use self::standard_broadcast_run::StandardBroadcastRun;
use crate::blocktree::Blocktree; use crate::blocktree::Blocktree;
use crate::cluster_info::{ClusterInfo, ClusterInfoError}; use crate::cluster_info::{ClusterInfo, ClusterInfoError};
use crate::erasure::CodingGenerator; use crate::erasure::{CodingGenerator, ErasureConfig};
use crate::poh_recorder::WorkingBankEntries; use crate::poh_recorder::WorkingBankEntries;
use crate::result::{Error, Result}; use crate::result::{Error, Result};
use crate::service::Service; use crate::service::Service;
@ -51,6 +51,7 @@ impl BroadcastStageType {
receiver: Receiver<WorkingBankEntries>, receiver: Receiver<WorkingBankEntries>,
exit_sender: &Arc<AtomicBool>, exit_sender: &Arc<AtomicBool>,
blocktree: &Arc<Blocktree>, blocktree: &Arc<Blocktree>,
erasure_config: &ErasureConfig,
) -> BroadcastStage { ) -> BroadcastStage {
match self { match self {
BroadcastStageType::Standard => BroadcastStage::new( BroadcastStageType::Standard => BroadcastStage::new(
@ -60,6 +61,7 @@ impl BroadcastStageType {
exit_sender, exit_sender,
blocktree, blocktree,
StandardBroadcastRun::new(), StandardBroadcastRun::new(),
erasure_config,
), ),
BroadcastStageType::FailEntryVerification => BroadcastStage::new( BroadcastStageType::FailEntryVerification => BroadcastStage::new(
@ -69,6 +71,7 @@ impl BroadcastStageType {
exit_sender, exit_sender,
blocktree, blocktree,
FailEntryVerificationBroadcastRun::new(), FailEntryVerificationBroadcastRun::new(),
erasure_config,
), ),
BroadcastStageType::BroadcastFakeBlobs => BroadcastStage::new( BroadcastStageType::BroadcastFakeBlobs => BroadcastStage::new(
@ -78,6 +81,7 @@ impl BroadcastStageType {
exit_sender, exit_sender,
blocktree, blocktree,
BroadcastFakeBlobsRun::new(0), BroadcastFakeBlobsRun::new(0),
erasure_config,
), ),
BroadcastStageType::BroadcastBadBlobSizes => BroadcastStage::new( BroadcastStageType::BroadcastBadBlobSizes => BroadcastStage::new(
@ -87,6 +91,7 @@ impl BroadcastStageType {
exit_sender, exit_sender,
blocktree, blocktree,
BroadcastBadBlobSizes::new(), BroadcastBadBlobSizes::new(),
erasure_config,
), ),
} }
} }
@ -138,8 +143,9 @@ impl BroadcastStage {
receiver: &Receiver<WorkingBankEntries>, receiver: &Receiver<WorkingBankEntries>,
blocktree: &Arc<Blocktree>, blocktree: &Arc<Blocktree>,
mut broadcast_stage_run: impl BroadcastRun, mut broadcast_stage_run: impl BroadcastRun,
erasure_config: &ErasureConfig,
) -> BroadcastStageReturnType { ) -> BroadcastStageReturnType {
let coding_generator = CodingGenerator::default(); let coding_generator = CodingGenerator::new_from_config(erasure_config);
let mut broadcast = Broadcast { let mut broadcast = Broadcast {
coding_generator, coding_generator,
@ -191,9 +197,11 @@ impl BroadcastStage {
exit_sender: &Arc<AtomicBool>, exit_sender: &Arc<AtomicBool>,
blocktree: &Arc<Blocktree>, blocktree: &Arc<Blocktree>,
broadcast_stage_run: impl BroadcastRun + Send + 'static, broadcast_stage_run: impl BroadcastRun + Send + 'static,
erasure_config: &ErasureConfig,
) -> Self { ) -> Self {
let blocktree = blocktree.clone(); let blocktree = blocktree.clone();
let exit_sender = exit_sender.clone(); let exit_sender = exit_sender.clone();
let erasure_config = *erasure_config;
let thread_hdl = Builder::new() let thread_hdl = Builder::new()
.name("solana-broadcaster".to_string()) .name("solana-broadcaster".to_string())
.spawn(move || { .spawn(move || {
@ -204,6 +212,7 @@ impl BroadcastStage {
&receiver, &receiver,
&blocktree, &blocktree,
broadcast_stage_run, broadcast_stage_run,
&erasure_config,
) )
}) })
.unwrap(); .unwrap();
@ -277,6 +286,7 @@ mod test {
&exit_sender, &exit_sender,
&blocktree, &blocktree,
StandardBroadcastRun::new(), StandardBroadcastRun::new(),
&ErasureConfig::default(),
); );
MockBroadcastStage { MockBroadcastStage {

View File

@ -135,7 +135,7 @@ mod tests {
hasher.hash(&buf[..size]); hasher.hash(&buf[..size]);
// golden needs to be updated if blob stuff changes.... // golden needs to be updated if blob stuff changes....
let golden: Hash = "5FzYtpCqL7v6ZxZ1fW4wRkn8TK96NdiD8cLV59Rr7yav" let golden: Hash = "Dy2V98ybxnp1mDTqXrUbsLE5LyKVpQN5zDhrEKCDEFhH"
.parse() .parse()
.unwrap(); .unwrap();

View File

@ -1652,6 +1652,7 @@ mod tests {
use crate::blocktree::tests::make_many_slot_entries; use crate::blocktree::tests::make_many_slot_entries;
use crate::blocktree::Blocktree; use crate::blocktree::Blocktree;
use crate::crds_value::CrdsValueLabel; use crate::crds_value::CrdsValueLabel;
use crate::erasure::ErasureConfig;
use crate::packet::BLOB_HEADER_SIZE; use crate::packet::BLOB_HEADER_SIZE;
use crate::repair_service::RepairType; use crate::repair_service::RepairType;
use crate::result::Error; use crate::result::Error;
@ -1816,6 +1817,7 @@ mod tests {
w_blob.set_size(data_size); w_blob.set_size(data_size);
w_blob.set_index(1); w_blob.set_index(1);
w_blob.set_slot(2); w_blob.set_slot(2);
w_blob.set_erasure_config(&ErasureConfig::default());
w_blob.meta.size = data_size + BLOB_HEADER_SIZE; w_blob.meta.size = data_size + BLOB_HEADER_SIZE;
} }
@ -1860,6 +1862,7 @@ mod tests {
blob.set_size(data_size); blob.set_size(data_size);
blob.set_index(i); blob.set_index(i);
blob.set_slot(2); blob.set_slot(2);
blob.set_erasure_config(&ErasureConfig::default());
blob.meta.size = data_size + BLOB_HEADER_SIZE; blob.meta.size = data_size + BLOB_HEADER_SIZE;
blob blob
}) })

View File

@ -55,6 +55,38 @@ pub const NUM_CODING: usize = 8;
/// Total number of blobs in an erasure set; includes data and coding blobs /// Total number of blobs in an erasure set; includes data and coding blobs
pub const ERASURE_SET_SIZE: usize = NUM_DATA + NUM_CODING; pub const ERASURE_SET_SIZE: usize = NUM_DATA + NUM_CODING;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct ErasureConfig {
num_data: usize,
num_coding: usize,
}
impl Default for ErasureConfig {
fn default() -> ErasureConfig {
ErasureConfig {
num_data: NUM_DATA,
num_coding: NUM_CODING,
}
}
}
impl ErasureConfig {
pub fn new(num_data: usize, num_coding: usize) -> ErasureConfig {
ErasureConfig {
num_data,
num_coding,
}
}
pub fn num_data(self) -> usize {
self.num_data
}
pub fn num_coding(self) -> usize {
self.num_coding
}
}
type Result<T> = std::result::Result<T, reed_solomon_erasure::Error>; type Result<T> = std::result::Result<T, reed_solomon_erasure::Error>;
/// Represents an erasure "session" with a particular configuration and number of data and coding /// Represents an erasure "session" with a particular configuration and number of data and coding
@ -77,6 +109,12 @@ impl Session {
Ok(Session(rs)) Ok(Session(rs))
} }
pub fn new_from_config(config: &ErasureConfig) -> Result<Session> {
let rs = ReedSolomon::new(config.num_data, config.num_coding)?;
Ok(Session(rs))
}
/// Create coding blocks by overwriting `parity` /// Create coding blocks by overwriting `parity`
pub fn encode(&self, data: &[&[u8]], parity: &mut [&mut [u8]]) -> Result<()> { pub fn encode(&self, data: &[&[u8]], parity: &mut [&mut [u8]]) -> Result<()> {
self.0.encode_sep(data, parity)?; self.0.encode_sep(data, parity)?;
@ -136,7 +174,7 @@ impl Session {
let idx; let idx;
let first_byte; let first_byte;
if n < NUM_DATA { if n < self.0.data_shard_count() {
let mut blob = Blob::new(&blocks[n]); let mut blob = Blob::new(&blocks[n]);
blob.meta.size = blob.data_size() as usize; blob.meta.size = blob.data_size() as usize;
@ -181,6 +219,13 @@ impl CodingGenerator {
} }
} }
pub fn new_from_config(config: &ErasureConfig) -> Self {
CodingGenerator {
leftover: Vec::with_capacity(config.num_data),
session: Arc::new(Session::new_from_config(config).unwrap()),
}
}
/// Yields next set of coding blobs, if any. /// Yields next set of coding blobs, if any.
/// Must be called with consecutive data blobs within a slot. /// Must be called with consecutive data blobs within a slot.
/// ///
@ -235,6 +280,7 @@ impl CodingGenerator {
coding_blob.set_id(&id); coding_blob.set_id(&id);
coding_blob.set_size(max_data_size); coding_blob.set_size(max_data_size);
coding_blob.set_coding(); coding_blob.set_coding();
coding_blob.set_erasure_config(&data_blob.erasure_config());
coding_blobs.push(coding_blob); coding_blobs.push(coding_blob);
} }
@ -744,6 +790,7 @@ pub mod test {
let mut blob = Blob::default(); let mut blob = Blob::default();
blob.data_mut()[..].copy_from_slice(&data); blob.data_mut()[..].copy_from_slice(&data);
blob.set_size(BLOB_DATA_SIZE); blob.set_size(BLOB_DATA_SIZE);
blob.set_erasure_config(&ErasureConfig::default());
Arc::new(RwLock::new(blob)) Arc::new(RwLock::new(blob))
}) })
.collect(); .collect();

View File

@ -1,5 +1,6 @@
//! The `packet` module defines data structures and methods to pull data from the network. //! The `packet` module defines data structures and methods to pull data from the network.
use crate::cuda_runtime::PinnedVec; use crate::cuda_runtime::PinnedVec;
use crate::erasure::ErasureConfig;
use crate::recvmmsg::{recv_mmsg, NUM_RCVMMSGS}; use crate::recvmmsg::{recv_mmsg, NUM_RCVMMSGS};
use crate::recycler::{Recycler, Reset}; use crate::recycler::{Recycler, Reset};
use crate::result::{Error, Result}; use crate::result::{Error, Result};
@ -389,7 +390,8 @@ const SLOT_RANGE: std::ops::Range<usize> = range!(PARENT_RANGE.end, u64);
const INDEX_RANGE: std::ops::Range<usize> = range!(SLOT_RANGE.end, u64); const INDEX_RANGE: std::ops::Range<usize> = range!(SLOT_RANGE.end, u64);
const ID_RANGE: std::ops::Range<usize> = range!(INDEX_RANGE.end, Pubkey); const ID_RANGE: std::ops::Range<usize> = range!(INDEX_RANGE.end, Pubkey);
const FLAGS_RANGE: std::ops::Range<usize> = range!(ID_RANGE.end, u32); const FLAGS_RANGE: std::ops::Range<usize> = range!(ID_RANGE.end, u32);
const SIZE_RANGE: std::ops::Range<usize> = range!(FLAGS_RANGE.end, u64); const ERASURE_CONFIG_RANGE: std::ops::Range<usize> = range!(FLAGS_RANGE.end, ErasureConfig);
const SIZE_RANGE: std::ops::Range<usize> = range!(ERASURE_CONFIG_RANGE.end, u64);
macro_rules! align { macro_rules! align {
($x:expr, $align:expr) => { ($x:expr, $align:expr) => {
@ -426,6 +428,7 @@ impl Blob {
out.position() as usize out.position() as usize
}; };
blob.set_size(pos); blob.set_size(pos);
blob.set_erasure_config(&ErasureConfig::default());
blob blob
} }
@ -448,6 +451,14 @@ impl Blob {
LittleEndian::write_u64(&mut self.data[INDEX_RANGE], ix); LittleEndian::write_u64(&mut self.data[INDEX_RANGE], ix);
} }
pub fn set_erasure_config(&mut self, config: &ErasureConfig) {
self.data[ERASURE_CONFIG_RANGE].copy_from_slice(&bincode::serialize(config).unwrap())
}
pub fn erasure_config(&self) -> ErasureConfig {
bincode::deserialize(&self.data[ERASURE_CONFIG_RANGE]).unwrap_or_default()
}
pub fn seed(&self) -> [u8; 32] { pub fn seed(&self) -> [u8; 32] {
let mut seed = [0; 32]; let mut seed = [0; 32];
let seed_len = seed.len(); let seed_len = seed.len();
@ -807,6 +818,15 @@ mod tests {
assert!(!b.should_forward()); assert!(!b.should_forward());
} }
#[test]
fn test_blob_erasure_config() {
let mut b = Blob::default();
let config = ErasureConfig::new(32, 16);
b.set_erasure_config(&config);
assert_eq!(config, b.erasure_config());
}
#[test] #[test]
fn test_store_blobs_max() { fn test_store_blobs_max() {
let serialized_size_size = bincode::serialized_size(&0usize).unwrap() as usize; let serialized_size_size = bincode::serialized_size(&0usize).unwrap() as usize;

View File

@ -687,6 +687,7 @@ mod test {
use super::*; use super::*;
use crate::blocktree::get_tmp_ledger_path; use crate::blocktree::get_tmp_ledger_path;
use crate::entry; use crate::entry;
use crate::erasure::ErasureConfig;
use crate::genesis_utils::create_genesis_block; use crate::genesis_utils::create_genesis_block;
use crate::packet::{Blob, BLOB_HEADER_SIZE}; use crate::packet::{Blob, BLOB_HEADER_SIZE};
use crate::replay_stage::ReplayStage; use crate::replay_stage::ReplayStage;
@ -716,6 +717,7 @@ mod test {
let mut blob_slot_1 = Blob::default(); let mut blob_slot_1 = Blob::default();
blob_slot_1.set_slot(1); blob_slot_1.set_slot(1);
blob_slot_1.set_parent(0); blob_slot_1.set_parent(0);
blob_slot_1.set_erasure_config(&ErasureConfig::default());
blocktree.insert_data_blobs(&vec![blob_slot_1]).unwrap(); blocktree.insert_data_blobs(&vec![blob_slot_1]).unwrap();
assert!(bank_forks.get(1).is_none()); assert!(bank_forks.get(1).is_none());
ReplayStage::generate_new_bank_forks( ReplayStage::generate_new_bank_forks(
@ -729,6 +731,7 @@ mod test {
let mut blob_slot_2 = Blob::default(); let mut blob_slot_2 = Blob::default();
blob_slot_2.set_slot(2); blob_slot_2.set_slot(2);
blob_slot_2.set_parent(0); blob_slot_2.set_parent(0);
blob_slot_2.set_erasure_config(&ErasureConfig::default());
blocktree.insert_data_blobs(&vec![blob_slot_2]).unwrap(); blocktree.insert_data_blobs(&vec![blob_slot_2]).unwrap();
assert!(bank_forks.get(2).is_none()); assert!(bank_forks.get(2).is_none());
ReplayStage::generate_new_bank_forks( ReplayStage::generate_new_bank_forks(

View File

@ -6,6 +6,7 @@ use crate::blocktree::Blocktree;
use crate::broadcast_stage::{BroadcastStage, BroadcastStageType}; use crate::broadcast_stage::{BroadcastStage, BroadcastStageType};
use crate::cluster_info::ClusterInfo; use crate::cluster_info::ClusterInfo;
use crate::cluster_info_vote_listener::ClusterInfoVoteListener; use crate::cluster_info_vote_listener::ClusterInfoVoteListener;
use crate::erasure::ErasureConfig;
use crate::fetch_stage::FetchStage; use crate::fetch_stage::FetchStage;
use crate::poh_recorder::{PohRecorder, WorkingBankEntries}; use crate::poh_recorder::{PohRecorder, WorkingBankEntries};
use crate::service::Service; use crate::service::Service;
@ -37,6 +38,7 @@ impl Tpu {
sigverify_disabled: bool, sigverify_disabled: bool,
blocktree: &Arc<Blocktree>, blocktree: &Arc<Blocktree>,
broadcast_type: &BroadcastStageType, broadcast_type: &BroadcastStageType,
erasure_config: &ErasureConfig,
exit: &Arc<AtomicBool>, exit: &Arc<AtomicBool>,
) -> Self { ) -> Self {
let (packet_sender, packet_receiver) = channel(); let (packet_sender, packet_receiver) = channel();
@ -74,6 +76,7 @@ impl Tpu {
entry_receiver, entry_receiver,
&exit, &exit,
blocktree, blocktree,
erasure_config,
); );
Self { Self {

View File

@ -6,6 +6,7 @@ use crate::blocktree_processor::{self, BankForksInfo};
use crate::broadcast_stage::BroadcastStageType; use crate::broadcast_stage::BroadcastStageType;
use crate::cluster_info::{ClusterInfo, Node}; use crate::cluster_info::{ClusterInfo, Node};
use crate::contact_info::ContactInfo; use crate::contact_info::ContactInfo;
use crate::erasure::ErasureConfig;
use crate::gossip_service::{discover_cluster, GossipService}; use crate::gossip_service::{discover_cluster, GossipService};
use crate::leader_schedule_cache::LeaderScheduleCache; use crate::leader_schedule_cache::LeaderScheduleCache;
use crate::poh_recorder::PohRecorder; use crate::poh_recorder::PohRecorder;
@ -40,6 +41,7 @@ pub struct ValidatorConfig {
pub rpc_config: JsonRpcConfig, pub rpc_config: JsonRpcConfig,
pub snapshot_path: Option<String>, pub snapshot_path: Option<String>,
pub broadcast_stage_type: BroadcastStageType, pub broadcast_stage_type: BroadcastStageType,
pub erasure_config: ErasureConfig,
} }
impl Default for ValidatorConfig { impl Default for ValidatorConfig {
@ -53,6 +55,7 @@ impl Default for ValidatorConfig {
rpc_config: JsonRpcConfig::default(), rpc_config: JsonRpcConfig::default(),
snapshot_path: None, snapshot_path: None,
broadcast_stage_type: BroadcastStageType::Standard, broadcast_stage_type: BroadcastStageType::Standard,
erasure_config: ErasureConfig::default(),
} }
} }
} }
@ -264,6 +267,7 @@ impl Validator {
config.sigverify_disabled, config.sigverify_disabled,
&blocktree, &blocktree,
&config.broadcast_stage_type, &config.broadcast_stage_type,
&config.erasure_config,
&exit, &exit,
); );