Encapsulate Bank accounts

That way we don't need to TODOs saying "don't forget to iterate
over checkpoints too". It should be assumed that when the bank
references its previous checkpoint all its methods would
acknowledge it.
This commit is contained in:
Greg Fitzgerald 2019-02-16 07:28:58 -07:00
parent 7981865fd2
commit 1809277e05
3 changed files with 41 additions and 48 deletions

View File

@ -32,7 +32,7 @@ use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::timing::duration_as_us; use solana_sdk::timing::duration_as_us;
use solana_sdk::token_program; use solana_sdk::token_program;
use solana_sdk::transaction::Transaction; use solana_sdk::transaction::Transaction;
use solana_sdk::vote_program; use solana_sdk::vote_program::{self, VoteState};
use std; use std;
use std::result; use std::result;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -93,7 +93,7 @@ type BankStatusCache = StatusCache<BankError>;
/// Manager for the state of all accounts and programs after processing its entries. /// Manager for the state of all accounts and programs after processing its entries.
pub struct Bank { pub struct Bank {
pub accounts: Accounts, accounts: Accounts,
/// A cache of signature statuses /// A cache of signature statuses
status_cache: RwLock<BankStatusCache>, status_cache: RwLock<BankStatusCache>,
@ -183,7 +183,7 @@ impl Bank {
executable: false, executable: false,
}; };
let mut vote_state = vote_program::VoteState::new( let mut vote_state = VoteState::new(
genesis_block.bootstrap_leader_id, genesis_block.bootstrap_leader_id,
genesis_block.bootstrap_leader_id, genesis_block.bootstrap_leader_id,
); );
@ -807,6 +807,29 @@ impl Bank {
} }
} }
pub fn vote_states<F>(&self, cond: F) -> Vec<VoteState>
where
F: Fn(&VoteState) -> bool,
{
self.accounts
.accounts_db
.read()
.unwrap()
.accounts
.values()
.filter_map(|account| {
if vote_program::check_id(&account.owner) {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
if cond(&vote_state) {
return Some(vote_state);
}
}
}
None
})
.collect()
}
#[cfg(test)] #[cfg(test)]
fn get_current_leader(&self) -> Option<Pubkey> { fn get_current_leader(&self) -> Option<Pubkey> {
let tick_height = self.tick_height(); let tick_height = self.tick_height();

View File

@ -8,7 +8,6 @@ use crate::service::Service;
use solana_metrics::{influxdb, submit}; use solana_metrics::{influxdb, submit};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing; use solana_sdk::timing;
use solana_sdk::vote_program::{self, 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;
@ -37,24 +36,7 @@ impl ComputeLeaderConfirmationService {
// 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: Vec<VoteState> = bank let vote_states = bank.vote_states(|vote_state| leader_id != vote_state.node_id);
.accounts
.accounts_db
.read()
.unwrap()
.accounts
.values()
.filter_map(|account| {
if vote_program::check_id(&account.owner) {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
if leader_id != vote_state.node_id {
return Some(vote_state);
}
}
}
None
})
.collect();
let mut ticks_and_stakes: Vec<(u64, u64)> = vote_states let mut ticks_and_stakes: Vec<(u64, u64)> = vote_states
.iter() .iter()

View File

@ -11,7 +11,7 @@ use solana_sdk::hash::{hash, Hash};
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction; use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::vote_program::{self, VoteState}; use solana_sdk::vote_program::VoteState;
use solana_sdk::vote_transaction::VoteTransaction; use solana_sdk::vote_transaction::VoteTransaction;
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc; use std::sync::Arc;
@ -195,6 +195,15 @@ impl LeaderScheduler {
} }
} }
// Return true of the latest vote is between the lower and upper bounds (inclusive)
fn is_active_staker(vote_state: &VoteState, lower_bound: u64, upper_bound: u64) -> bool {
vote_state
.votes
.back()
.filter(|vote| vote.tick_height >= lower_bound && vote.tick_height <= upper_bound)
.is_some()
}
// TODO: We use a HashSet for now because a single validator could potentially register // TODO: We use a HashSet for now because a single validator could potentially register
// multiple vote account. Once that is no longer possible (see the TODO in vote_program.rs, // multiple vote account. Once that is no longer possible (see the TODO in vote_program.rs,
// process_transaction(), case VoteInstruction::RegisterAccount), we can use a vector. // process_transaction(), case VoteInstruction::RegisterAccount), we can use a vector.
@ -207,32 +216,11 @@ impl LeaderScheduler {
upper_bound upper_bound
); );
{ bank.vote_states(|vote_state| Self::is_active_staker(vote_state, lower_bound, upper_bound))
let accounts = bank.accounts.accounts_db.read().unwrap(); .iter()
// TODO: iterate through checkpoints, too .map(|vote_state| vote_state.staker_id)
accounts
.accounts
.values()
.filter_map(|account| {
if vote_program::check_id(&account.owner) {
if let Ok(vote_state) = VoteState::deserialize(&account.userdata) {
trace!("get_active_set: account vote_state: {:?}", vote_state);
return vote_state
.votes
.back()
.filter(|vote| {
vote.tick_height >= lower_bound
&& vote.tick_height <= upper_bound
})
.map(|_| vote_state.staker_id);
}
}
None
})
.collect() .collect()
} }
}
// Updates the leader schedule to include ticks from tick_height to the first tick of the next epoch // Updates the leader schedule to include ticks from tick_height to the first tick of the next epoch
fn generate_schedule(&mut self, tick_height: u64, bank: &Bank) { fn generate_schedule(&mut self, tick_height: u64, bank: &Bank) {