Refactor bank get vote accounts (#3052)
This commit is contained in:
parent
f4c5b9ccb0
commit
d22a13257e
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue