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

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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