Refactor bank get vote accounts (#3052)

This commit is contained in:
Sagar Dhawan 2019-03-02 13:23:55 -08:00 committed by Michael Vines
parent f4c5b9ccb0
commit d22a13257e
No known key found for this signature in database
GPG Key ID: 33F4FDEC4E0E88BD
7 changed files with 46 additions and 101 deletions

View File

@ -118,13 +118,8 @@ fn bench_banking_stage_multi_accounts(bencher: &mut Bencher) {
})
.collect();
let (poh_recorder, poh_service) = create_test_recorder(&bank);
let (_stage, signal_receiver) = BankingStage::new(
&bank,
&poh_recorder,
verified_receiver,
std::u64::MAX,
genesis_block.bootstrap_leader_id,
);
let (_stage, signal_receiver) =
BankingStage::new(&bank, &poh_recorder, verified_receiver, std::u64::MAX);
let mut id = genesis_block.hash();
for _ in 0..MAX_RECENT_TICK_HASHES {
@ -227,13 +222,8 @@ fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
})
.collect();
let (poh_recorder, poh_service) = create_test_recorder(&bank);
let (_stage, signal_receiver) = BankingStage::new(
&bank,
&poh_recorder,
verified_receiver,
std::u64::MAX,
genesis_block.bootstrap_leader_id,
);
let (_stage, signal_receiver) =
BankingStage::new(&bank, &poh_recorder, verified_receiver, std::u64::MAX);
let mut id = genesis_block.hash();
for _ in 0..MAX_RECENT_TICK_HASHES {

View File

@ -13,7 +13,6 @@ use crate::sigverify_stage::VerifiedPackets;
use bincode::deserialize;
use solana_metrics::counter::Counter;
use solana_runtime::bank::{self, Bank, BankError};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing::{self, duration_as_us, MAX_RECENT_TICK_HASHES};
use solana_sdk::transaction::Transaction;
use std::sync::atomic::{AtomicBool, Ordering};
@ -44,7 +43,6 @@ impl BankingStage {
poh_recorder: &Arc<Mutex<PohRecorder>>,
verified_receiver: Receiver<VerifiedPackets>,
max_tick_height: u64,
leader_id: Pubkey,
) -> (Self, Receiver<Vec<(Entry, u64)>>) {
let (entry_sender, entry_receiver) = channel();
let working_bank = WorkingBank {
@ -70,8 +68,7 @@ impl BankingStage {
let exit = Arc::new(AtomicBool::new(false));
// Single thread to compute confirmation
let leader_confirmation_service =
LeaderConfirmationService::new(&bank, leader_id, exit.clone());
let leader_confirmation_service = LeaderConfirmationService::new(&bank, exit.clone());
// Many banks that process transactions in parallel.
let bank_thread_hdls: Vec<JoinHandle<UnprocessedPackets>> = (0..Self::num_threads())
@ -382,7 +379,6 @@ mod tests {
&poh_recorder,
verified_receiver,
DEFAULT_TICKS_PER_SLOT,
genesis_block.bootstrap_leader_id,
);
drop(verified_sender);
banking_stage.join().unwrap();
@ -402,7 +398,6 @@ mod tests {
&poh_recorder,
verified_receiver,
genesis_block.ticks_per_slot - 1,
genesis_block.bootstrap_leader_id,
);
sleep(Duration::from_millis(600));
drop(verified_sender);
@ -430,7 +425,6 @@ mod tests {
&poh_recorder,
verified_receiver,
DEFAULT_TICKS_PER_SLOT,
genesis_block.bootstrap_leader_id,
);
// good tx
@ -489,7 +483,6 @@ mod tests {
&poh_recorder,
verified_receiver,
DEFAULT_TICKS_PER_SLOT,
genesis_block.bootstrap_leader_id,
);
// Process a batch that includes a transaction that receives two tokens.
@ -552,13 +545,8 @@ mod tests {
let (verified_sender, verified_receiver) = channel();
let max_tick_height = 10;
let (poh_recorder, poh_service) = create_test_recorder(&bank);
let (banking_stage, _entry_receiver) = BankingStage::new(
&bank,
&poh_recorder,
verified_receiver,
max_tick_height,
genesis_block.bootstrap_leader_id,
);
let (banking_stage, _entry_receiver) =
BankingStage::new(&bank, &poh_recorder, verified_receiver, max_tick_height);
loop {
let bank_tick_height = bank.tick_height();
@ -581,13 +569,8 @@ mod tests {
let ticks_per_slot = 1;
let (verified_sender, verified_receiver) = channel();
let (poh_recorder, poh_service) = create_test_recorder(&bank);
let (mut banking_stage, _entry_receiver) = BankingStage::new(
&bank,
&poh_recorder,
verified_receiver,
ticks_per_slot,
genesis_block.bootstrap_leader_id,
);
let (mut banking_stage, _entry_receiver) =
BankingStage::new(&bank, &poh_recorder, verified_receiver, ticks_per_slot);
// Wait for Poh recorder to hit max height
loop {

View File

@ -5,8 +5,8 @@
use crate::service::Service;
use solana_metrics::{influxdb, submit};
use solana_runtime::bank::Bank;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing;
use solana_sdk::vote_program::VoteState;
use std::result;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@ -28,26 +28,23 @@ pub struct LeaderConfirmationService {
impl LeaderConfirmationService {
fn get_last_supermajority_timestamp(
bank: &Arc<Bank>,
leader_id: Pubkey,
last_valid_validator_timestamp: u64,
) -> result::Result<u64, ConfirmationError> {
let mut total_stake = 0;
let mut slots_and_stakes: Vec<(u64, u64)> = vec![];
// Hold an accounts_db read lock as briefly as possible, just long enough to collect all
// the vote states
let vote_states = bank.vote_states(|_, vote_state| leader_id != vote_state.delegate_id);
let slots_and_stakes: Vec<(u64, u64)> = vote_states
.iter()
.filter_map(|(_, vote_state)| {
let validator_stake = bank.get_balance(&vote_state.delegate_id);
total_stake += validator_stake;
vote_state
.votes
.back()
.map(|vote| (vote.slot_height, validator_stake))
})
.collect();
bank.vote_accounts().for_each(|(_, account)| {
total_stake += account.tokens;
let vote_state = VoteState::deserialize(&account.userdata).unwrap();
if let Some(stake_and_state) = vote_state
.votes
.back()
.map(|vote| (vote.slot_height, account.tokens))
{
slots_and_stakes.push(stake_and_state);
}
});
let super_majority_stake = (2 * total_stake) / 3;
@ -72,13 +69,9 @@ impl LeaderConfirmationService {
Err(ConfirmationError::NoValidSupermajority)
}
pub fn compute_confirmation(
bank: &Arc<Bank>,
leader_id: Pubkey,
last_valid_validator_timestamp: &mut u64,
) {
pub fn compute_confirmation(bank: &Arc<Bank>, last_valid_validator_timestamp: &mut u64) {
if let Ok(super_majority_timestamp) =
Self::get_last_supermajority_timestamp(bank, leader_id, *last_valid_validator_timestamp)
Self::get_last_supermajority_timestamp(bank, *last_valid_validator_timestamp)
{
let now = timing::timestamp();
let confirmation_ms = now - super_majority_timestamp;
@ -97,7 +90,7 @@ impl LeaderConfirmationService {
}
/// Create a new LeaderConfirmationService for computing confirmation.
pub fn new(bank: &Arc<Bank>, leader_id: Pubkey, exit: Arc<AtomicBool>) -> Self {
pub fn new(bank: &Arc<Bank>, exit: Arc<AtomicBool>) -> Self {
let bank = bank.clone();
let thread_hdl = Builder::new()
.name("solana-leader-confirmation-service".to_string())
@ -107,11 +100,7 @@ impl LeaderConfirmationService {
if exit.load(Ordering::Relaxed) {
break;
}
Self::compute_confirmation(
&bank,
leader_id,
&mut last_valid_validator_timestamp,
);
Self::compute_confirmation(&bank, &mut last_valid_validator_timestamp);
sleep(Duration::from_millis(COMPUTE_CONFIRMATION_MS));
}
})
@ -179,11 +168,7 @@ mod tests {
// There isn't 2/3 consensus, so the bank's confirmation value should be the default
let mut last_confirmation_time = 0;
LeaderConfirmationService::compute_confirmation(
&bank,
genesis_block.bootstrap_leader_id,
&mut last_confirmation_time,
);
LeaderConfirmationService::compute_confirmation(&bank, &mut last_confirmation_time);
assert_eq!(last_confirmation_time, 0);
// Get another validator to vote, so we now have 2/3 consensus
@ -191,11 +176,7 @@ mod tests {
let vote_tx = VoteTransaction::new_vote(voting_keypair, 7, blockhash, 0);
bank.process_transaction(&vote_tx).unwrap();
LeaderConfirmationService::compute_confirmation(
&bank,
genesis_block.bootstrap_leader_id,
&mut last_confirmation_time,
);
LeaderConfirmationService::compute_confirmation(&bank, &mut last_confirmation_time);
assert!(last_confirmation_time > 0);
}
}

View File

@ -226,13 +226,8 @@ impl Tpu {
.map(|meta| meta.consumed)
.unwrap_or(0);
let (banking_stage, entry_receiver) = BankingStage::new(
&bank,
poh_recorder,
verified_receiver,
max_tick_height,
self.id,
);
let (banking_stage, entry_receiver) =
BankingStage::new(&bank, poh_recorder, verified_receiver, max_tick_height);
let broadcast_stage = BroadcastStage::new(
slot,

Binary file not shown.

View File

@ -906,12 +906,11 @@ impl Accounts {
self.accounts_db.squash(fork);
}
pub fn get_vote_accounts(&self, fork: Fork) -> HashMap<Pubkey, Account> {
pub fn get_vote_accounts(&self, fork: Fork) -> impl Iterator<Item = (Pubkey, Account)> {
self.accounts_db
.get_vote_accounts(fork)
.into_iter()
.filter(|(_, acc)| acc.tokens != 0)
.collect()
}
}
@ -1600,26 +1599,31 @@ mod tests {
accounts.new_from_parent(1, 0);
assert_eq!(accounts.get_vote_accounts(1).len(), 1);
let mut vote_accounts: Vec<_> = accounts.get_vote_accounts(1).collect();
assert_eq!(vote_accounts.len(), 1);
vote_account.tokens = 0;
accounts.store_slow(1, &key, &vote_account);
assert_eq!(accounts.get_vote_accounts(1).len(), 0);
vote_accounts = accounts.get_vote_accounts(1).collect();
assert_eq!(vote_accounts.len(), 0);
let mut vote_account1 = Account::new(2, 0, vote_program::id());
let key1 = Keypair::new().pubkey();
accounts.store_slow(1, &key1, &vote_account1);
accounts.squash(1);
assert_eq!(accounts.get_vote_accounts(0).len(), 1);
assert_eq!(accounts.get_vote_accounts(1).len(), 1);
vote_accounts = accounts.get_vote_accounts(0).collect();
assert_eq!(vote_accounts.len(), 1);
vote_accounts = accounts.get_vote_accounts(1).collect();
assert_eq!(vote_accounts.len(), 1);
vote_account1.tokens = 0;
accounts.store_slow(1, &key1, &vote_account1);
accounts.store_slow(0, &key, &vote_account);
assert_eq!(accounts.get_vote_accounts(1).len(), 0);
vote_accounts = accounts.get_vote_accounts(1).collect();
assert_eq!(vote_accounts.len(), 0);
}
#[test]

View File

@ -142,7 +142,7 @@ impl Bank {
// genesis needs stakes for all epochs up to the epoch implied by
// slot = 0 and genesis configuration
let vote_accounts = bank.vote_accounts(|k, v| Some((*k, v.clone())));
let vote_accounts: HashMap<_, _> = bank.vote_accounts().collect();
for i in 0..=bank.epoch_from_stakers_slot_offset() {
bank.epoch_vote_accounts.insert(i, vote_accounts.clone());
}
@ -182,7 +182,7 @@ impl Bank {
// if my parent didn't populate for this epoch, we've
// crossed a boundary
if epoch_vote_accounts.get(&epoch).is_none() {
epoch_vote_accounts.insert(epoch, bank.vote_accounts(|k, v| Some((*k, v.clone()))));
epoch_vote_accounts.insert(epoch, bank.vote_accounts().collect());
}
epoch_vote_accounts
};
@ -787,15 +787,8 @@ impl Bank {
}
/// current vote accounts for this bank
pub fn vote_accounts<F, T>(&self, filter: F) -> HashMap<Pubkey, T>
where
F: Fn(&Pubkey, &Account) -> Option<(Pubkey, T)>,
{
self.accounts()
.get_vote_accounts(self.accounts_id)
.iter()
.filter_map(|(pubkey, account)| filter(pubkey, account))
.collect()
pub fn vote_accounts(&self) -> impl Iterator<Item = (Pubkey, Account)> {
self.accounts().get_vote_accounts(self.accounts_id)
}
/// vote accounts for the specific epoch
@ -817,11 +810,10 @@ impl Bank {
{
self.accounts()
.get_vote_accounts(self.accounts_id)
.iter()
.filter_map(|(p, account)| {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
if cond(&p, &vote_state) {
return Some((*p, vote_state));
return Some((p, vote_state));
}
}
None