Handle missed slots in storage stage (#4337)

* Handle missed slots in storage stage

* Fix test compile

* Make test use the new missed slot support
This commit is contained in:
Sagar Dhawan 2019-05-18 15:24:50 -07:00 committed by GitHub
parent 167890ca63
commit 06eb2364f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 49 deletions

View File

@ -83,7 +83,7 @@ impl ReplayStage {
subscriptions: &Arc<RpcSubscriptions>,
poh_recorder: &Arc<Mutex<PohRecorder>>,
leader_schedule_cache: &Arc<LeaderScheduleCache>,
) -> (Self, Receiver<(u64, Pubkey)>, Receiver<u64>)
) -> (Self, Receiver<(u64, Pubkey)>, Receiver<Vec<u64>>)
where
T: 'static + KeypairUtil + Send + Sync,
{
@ -302,17 +302,23 @@ impl ReplayStage {
cluster_info: &Arc<RwLock<ClusterInfo>>,
blocktree: &Arc<Blocktree>,
leader_schedule_cache: &Arc<LeaderScheduleCache>,
root_slot_sender: &Sender<u64>,
root_slot_sender: &Sender<Vec<u64>>,
) -> Result<()>
where
T: 'static + KeypairUtil + Send + Sync,
{
if let Some(new_root) = locktower.record_vote(bank.slot()) {
let mut rooted_slots = bank
.parents()
.into_iter()
.map(|bank| bank.slot())
.collect::<Vec<_>>();
rooted_slots.push(bank.slot());
bank_forks.write().unwrap().set_root(new_root);
leader_schedule_cache.set_root(new_root);
blocktree.set_root(new_root)?;
Self::handle_new_root(&bank_forks, progress);
root_slot_sender.send(new_root)?;
root_slot_sender.send(rooted_slots)?;
}
locktower.update_epoch(&bank);
if let Some(ref voting_keypair) = voting_keypair {

View File

@ -132,7 +132,7 @@ impl StorageStage {
#[allow(clippy::too_many_arguments)]
pub fn new(
storage_state: &StorageState,
slot_receiver: Receiver<u64>,
slot_receiver: Receiver<Vec<u64>>,
blocktree: Option<Arc<Blocktree>>,
keypair: &Arc<Keypair>,
storage_keypair: &Arc<Keypair>,
@ -152,6 +152,7 @@ impl StorageStage {
.spawn(move || {
let mut current_key = 0;
let mut slot_count = 0;
let mut last_root = 0;
loop {
if let Some(ref some_blocktree) = blocktree {
if let Err(e) = Self::process_entries(
@ -160,6 +161,7 @@ impl StorageStage {
&slot_receiver,
&some_blocktree,
&mut slot_count,
&mut last_root,
&mut current_key,
storage_rotate_count,
&instruction_sender,
@ -391,53 +393,58 @@ impl StorageStage {
fn process_entries(
storage_keypair: &Arc<Keypair>,
storage_state: &Arc<RwLock<StorageStateInner>>,
slot_receiver: &Receiver<u64>,
slot_receiver: &Receiver<Vec<u64>>,
blocktree: &Arc<Blocktree>,
slot_count: &mut u64,
last_root: &mut u64,
current_key_idx: &mut usize,
storage_rotate_count: u64,
instruction_sender: &InstructionSender,
) -> Result<()> {
let timeout = Duration::new(1, 0);
let slot: u64 = slot_receiver.recv_timeout(timeout)?;
*slot_count += 1;
// Todo check if any rooted slots were missed leading up to this one and bump slot count and process proofs for each missed root
// Update the advertised blockhash to the latest root directly.
let slots: Vec<u64> = slot_receiver.recv_timeout(timeout)?;
// check if any rooted slots were missed leading up to this one and bump slot count and process proofs for each missed root
for slot in slots.into_iter().rev() {
if slot > *last_root {
*slot_count += 1;
*last_root = slot;
if let Ok(entries) = blocktree.get_slot_entries(slot, 0, None) {
for entry in &entries {
// Go through the transactions, find proofs, and use them to update
// the storage_keys with their signatures
for tx in &entry.transactions {
for (i, program_id) in tx.message.program_ids().iter().enumerate() {
if solana_storage_api::check_id(&program_id) {
Self::process_storage_transaction(
&tx.message().instructions[i].data,
slot,
storage_state,
current_key_idx,
tx.message.account_keys[0],
);
if let Ok(entries) = blocktree.get_slot_entries(slot, 0, None) {
for entry in &entries {
// Go through the transactions, find proofs, and use them to update
// the storage_keys with their signatures
for tx in &entry.transactions {
for (i, program_id) in tx.message.program_ids().iter().enumerate() {
if solana_storage_api::check_id(&program_id) {
Self::process_storage_transaction(
&tx.message().instructions[i].data,
slot,
storage_state,
current_key_idx,
tx.message.account_keys[0],
);
}
}
}
}
if *slot_count % storage_rotate_count == 0 {
// assume the last entry in the slot is the blockhash for that slot
let entry_hash = entries.last().unwrap().hash;
debug!(
"crosses sending at root slot: {}! with last entry's hash {}",
slot_count, entry_hash
);
Self::process_entry_crossing(
&storage_keypair,
&storage_state,
&blocktree,
entries.last().unwrap().hash,
slot,
instruction_sender,
)?;
}
}
}
if *slot_count % storage_rotate_count == 0 {
// assume the last entry in the slot is the blockhash for that slot
let entry_hash = entries.last().unwrap().hash;
debug!(
"crosses sending at root slot: {}! with last entry's hash {}",
slot_count, entry_hash
);
Self::process_entry_crossing(
&storage_keypair,
&storage_state,
&blocktree,
entries.last().unwrap().hash,
slot,
instruction_sender,
)?;
}
}
Ok(())
}
@ -543,7 +550,7 @@ mod tests {
STORAGE_ROTATE_TEST_COUNT,
&cluster_info,
);
slot_sender.send(slot).unwrap();
slot_sender.send(vec![slot]).unwrap();
let keypair = Keypair::new();
let hash = Hash::default();
@ -551,13 +558,15 @@ mod tests {
let mut result = storage_state.get_mining_result(&signature);
assert_eq!(result, Hash::default());
for i in slot..slot + SLOTS_PER_SEGMENT + 1 {
blocktree
.write_entries(i, 0, 0, ticks_per_slot, &entries)
.unwrap();
slot_sender.send(i).unwrap();
}
let rooted_slots = (slot..slot + SLOTS_PER_SEGMENT + 1)
.map(|i| {
blocktree
.write_entries(i, 0, 0, ticks_per_slot, &entries)
.unwrap();
i
})
.collect::<Vec<_>>();
slot_sender.send(rooted_slots).unwrap();
for _ in 0..5 {
result = storage_state.get_mining_result(&signature);
if result != Hash::default() {
@ -614,7 +623,7 @@ mod tests {
STORAGE_ROTATE_TEST_COUNT,
&cluster_info,
);
slot_sender.send(1).unwrap();
slot_sender.send(vec![1]).unwrap();
let mut reference_keys;
{
@ -637,7 +646,7 @@ mod tests {
blocktree
.write_entries(2, 0, 0, ticks_per_slot, &proof_entries)
.unwrap();
slot_sender.send(2).unwrap();
slot_sender.send(vec![2]).unwrap();
for _ in 0..5 {
{