compute_bank_stats needs to return newly computed ForkStats (#8608)

* Fix broken confirmation, add test
This commit is contained in:
carllin 2020-03-04 11:49:56 -08:00 committed by GitHub
parent 09a0325534
commit f23dc11a86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 151 additions and 2 deletions

View File

@ -852,7 +852,7 @@ impl ReplayStage {
progress: &mut ProgressMap,
) -> Vec<Slot> {
frozen_banks.sort_by_key(|bank| bank.slot());
let new_stats = vec![];
let mut new_stats = vec![];
for bank in frozen_banks {
// Only time progress map should be missing a bank slot
// is if this node was the leader for this slot as those banks
@ -895,6 +895,7 @@ impl ReplayStage {
stats.stake_lockouts = stake_lockouts;
stats.block_height = bank.block_height();
stats.computed = true;
new_stats.push(stats.slot);
}
stats.vote_threshold = tower.check_vote_stake_threshold(
bank.slot(),
@ -1171,6 +1172,7 @@ impl ReplayStage {
bank: Arc<Bank>,
slot_full_senders: &[Sender<(u64, Pubkey)>],
) {
info!("bank frozen: {}", bank.slot());
bank.freeze();
slot_full_senders.iter().for_each(|sender| {
if let Err(e) = sender.send((bank.slot(), *bank.collector_id())) {
@ -1306,7 +1308,10 @@ pub(crate) mod tests {
transaction::TransactionError,
};
use solana_stake_program::stake_state;
use solana_vote_program::vote_state::{self, Vote, VoteState, VoteStateVersions};
use solana_vote_program::{
vote_state::{self, Vote, VoteState, VoteStateVersions},
vote_transaction,
};
use std::{
fs::remove_dir_all,
iter,
@ -2157,6 +2162,119 @@ pub(crate) mod tests {
Blockstore::destroy(&ledger_path).unwrap();
}
#[test]
fn test_compute_bank_stats_confirmed() {
let node_keypair = Keypair::new();
let vote_keypair = Keypair::new();
let stake_keypair = Keypair::new();
let node_pubkey = node_keypair.pubkey();
let mut keypairs = HashMap::new();
keypairs.insert(
node_pubkey,
ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair),
);
let (bank_forks, mut progress) = initialize_state(&keypairs);
let bank0 = bank_forks.get(0).unwrap().clone();
let my_keypairs = keypairs.get(&node_pubkey).unwrap();
let vote_tx = vote_transaction::new_vote_transaction(
vec![0],
bank0.hash(),
bank0.last_blockhash(),
&my_keypairs.node_keypair,
&my_keypairs.vote_keypair,
&my_keypairs.vote_keypair,
);
let bank_forks = RwLock::new(bank_forks);
let bank1 = Bank::new_from_parent(&bank0, &node_pubkey, 1);
bank1.process_transaction(&vote_tx).unwrap();
bank1.freeze();
// Test confirmations
let ancestors = bank_forks.read().unwrap().ancestors();
let mut frozen_banks: Vec<_> = bank_forks
.read()
.unwrap()
.frozen_banks()
.values()
.cloned()
.collect();
let tower = Tower::new_for_tests(0, 0.67);
let newly_computed = ReplayStage::compute_bank_stats(
&node_pubkey,
&ancestors,
&mut frozen_banks,
&tower,
&mut progress,
);
assert_eq!(newly_computed, vec![0]);
// The only vote is in bank 1, and bank_forks does not currently contain
// bank 1, so no slot should be confirmed.
{
let fork_progress = progress.get(&0).unwrap();
let confirmed_forks = ReplayStage::confirm_forks(
&tower,
&fork_progress.fork_stats.stake_lockouts,
fork_progress.fork_stats.total_staked,
&progress,
&bank_forks,
);
assert!(confirmed_forks.is_empty())
}
// Insert the bank that contains a vote for slot 0, which confirms slot 0
bank_forks.write().unwrap().insert(bank1);
progress.insert(1, ForkProgress::new(bank0.last_blockhash()));
let ancestors = bank_forks.read().unwrap().ancestors();
let mut frozen_banks: Vec<_> = bank_forks
.read()
.unwrap()
.frozen_banks()
.values()
.cloned()
.collect();
let newly_computed = ReplayStage::compute_bank_stats(
&node_pubkey,
&ancestors,
&mut frozen_banks,
&tower,
&mut progress,
);
assert_eq!(newly_computed, vec![1]);
{
let fork_progress = progress.get(&1).unwrap();
let confirmed_forks = ReplayStage::confirm_forks(
&tower,
&fork_progress.fork_stats.stake_lockouts,
fork_progress.fork_stats.total_staked,
&progress,
&bank_forks,
);
assert_eq!(confirmed_forks, vec![0]);
}
let ancestors = bank_forks.read().unwrap().ancestors();
let mut frozen_banks: Vec<_> = bank_forks
.read()
.unwrap()
.frozen_banks()
.values()
.cloned()
.collect();
let newly_computed = ReplayStage::compute_bank_stats(
&node_pubkey,
&ancestors,
&mut frozen_banks,
&tower,
&mut progress,
);
// No new stats should have been computed
assert!(newly_computed.is_empty());
}
#[test]
fn test_child_bank_heavier() {
let node_keypair = Keypair::new();

View File

@ -1,6 +1,7 @@
pub mod authorized_voters;
pub mod vote_instruction;
pub mod vote_state;
pub mod vote_transaction;
#[macro_use]
extern crate solana_metrics;

View File

@ -0,0 +1,30 @@
use solana_sdk::{
clock::Slot,
hash::Hash,
signature::{Keypair, Signer},
transaction::Transaction,
};
use crate::{vote_instruction, vote_state::Vote};
pub fn new_vote_transaction(
slots: Vec<Slot>,
bank_hash: Hash,
blockhash: Hash,
node_keypair: &Keypair,
vote_keypair: &Keypair,
authorized_voter_keypair: &Keypair,
) -> Transaction {
let votes = Vote::new(slots, bank_hash);
let vote_ix = vote_instruction::vote(
&vote_keypair.pubkey(),
&authorized_voter_keypair.pubkey(),
votes,
);
let mut vote_tx = Transaction::new_with_payer(vec![vote_ix], Some(&node_keypair.pubkey()));
vote_tx.partial_sign(&[node_keypair], blockhash);
vote_tx.partial_sign(&[authorized_voter_keypair], blockhash);
vote_tx
}