Refactor bank get vote accounts (#3052)
This commit is contained in:
committed by
Michael Vines
parent
f4c5b9ccb0
commit
d22a13257e
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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)| {
|
.votes
|
||||||
let validator_stake = bank.get_balance(&vote_state.delegate_id);
|
.back()
|
||||||
total_stake += validator_stake;
|
.map(|vote| (vote.slot_height, account.tokens))
|
||||||
vote_state
|
{
|
||||||
.votes
|
slots_and_stakes.push(stake_and_state);
|
||||||
.back()
|
}
|
||||||
.map(|vote| (vote.slot_height, validator_stake))
|
});
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
@ -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]
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user