expose stake directly from bank (#4281)
This commit is contained in:
parent
0f498e6265
commit
216e9a61a0
|
@ -54,13 +54,13 @@ impl EpochStakes {
|
||||||
&Pubkey::default(),
|
&Pubkey::default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn new_from_stake_accounts(epoch: u64, accounts: &[(Pubkey, Account)]) -> Self {
|
pub fn new_from_stakes(epoch: u64, accounts: &[(Pubkey, (u64, Account))]) -> Self {
|
||||||
let stakes = accounts.iter().map(|(k, v)| (*k, v.lamports)).collect();
|
let stakes = accounts.iter().map(|(k, (v, _))| (*k, *v)).collect();
|
||||||
Self::new(epoch, stakes, &accounts[0].0)
|
Self::new(epoch, stakes, &accounts[0].0)
|
||||||
}
|
}
|
||||||
pub fn new_from_bank(bank: &Bank, my_id: &Pubkey) -> Self {
|
pub fn new_from_bank(bank: &Bank, my_id: &Pubkey) -> Self {
|
||||||
let bank_epoch = bank.get_epoch_and_slot_index(bank.slot()).0;
|
let bank_epoch = bank.get_epoch_and_slot_index(bank.slot()).0;
|
||||||
let stakes = staking_utils::vote_account_balances_at_epoch(bank, bank_epoch)
|
let stakes = staking_utils::vote_account_stakes_at_epoch(bank, bank_epoch)
|
||||||
.expect("voting require a bank with stakes");
|
.expect("voting require a bank with stakes");
|
||||||
Self::new(bank_epoch, stakes, my_id)
|
Self::new(bank_epoch, stakes, my_id)
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,10 @@ impl Locktower {
|
||||||
ancestors: &HashMap<u64, HashSet<u64>>,
|
ancestors: &HashMap<u64, HashSet<u64>>,
|
||||||
) -> HashMap<u64, StakeLockout>
|
) -> HashMap<u64, StakeLockout>
|
||||||
where
|
where
|
||||||
F: Iterator<Item = (Pubkey, Account)>,
|
F: Iterator<Item = (Pubkey, (u64, Account))>,
|
||||||
{
|
{
|
||||||
let mut stake_lockouts = HashMap::new();
|
let mut stake_lockouts = HashMap::new();
|
||||||
for (key, account) in vote_accounts {
|
for (key, (_, account)) in vote_accounts {
|
||||||
let lamports: u64 = *self.epoch_stakes.stakes.get(&key).unwrap_or(&0);
|
let lamports: u64 = *self.epoch_stakes.stakes.get(&key).unwrap_or(&0);
|
||||||
if lamports == 0 {
|
if lamports == 0 {
|
||||||
continue;
|
continue;
|
||||||
|
@ -361,7 +361,7 @@ impl Locktower {
|
||||||
fn initialize_lockouts_from_bank(bank: &Bank, current_epoch: u64) -> VoteState {
|
fn initialize_lockouts_from_bank(bank: &Bank, current_epoch: u64) -> VoteState {
|
||||||
let mut lockouts = VoteState::default();
|
let mut lockouts = VoteState::default();
|
||||||
if let Some(iter) = staking_utils::node_staked_accounts_at_epoch(&bank, current_epoch) {
|
if let Some(iter) = staking_utils::node_staked_accounts_at_epoch(&bank, current_epoch) {
|
||||||
for (delegate_id, _, account) in iter {
|
for (delegate_id, (_, account)) in iter {
|
||||||
if *delegate_id == bank.collector_id() {
|
if *delegate_id == bank.collector_id() {
|
||||||
let state = VoteState::deserialize(&account.data).expect("votes");
|
let state = VoteState::deserialize(&account.data).expect("votes");
|
||||||
if lockouts.votes.len() < state.votes.len() {
|
if lockouts.votes.len() < state.votes.len() {
|
||||||
|
@ -378,8 +378,8 @@ impl Locktower {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn gen_accounts(stake_votes: &[(u64, &[u64])]) -> Vec<(Pubkey, Account)> {
|
fn gen_stakes(stake_votes: &[(u64, &[u64])]) -> Vec<(Pubkey, (u64, Account))> {
|
||||||
let mut accounts = vec![];
|
let mut stakes = vec![];
|
||||||
for (lamports, votes) in stake_votes {
|
for (lamports, votes) in stake_votes {
|
||||||
let mut account = Account::default();
|
let mut account = Account::default();
|
||||||
account.data = vec![0; 1024];
|
account.data = vec![0; 1024];
|
||||||
|
@ -391,14 +391,14 @@ mod test {
|
||||||
vote_state
|
vote_state
|
||||||
.serialize(&mut account.data)
|
.serialize(&mut account.data)
|
||||||
.expect("serialize state");
|
.expect("serialize state");
|
||||||
accounts.push((Pubkey::new_rand(), account));
|
stakes.push((Pubkey::new_rand(), (*lamports, account)));
|
||||||
}
|
}
|
||||||
accounts
|
stakes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collect_vote_lockouts_no_epoch_stakes() {
|
fn test_collect_vote_lockouts_no_epoch_stakes() {
|
||||||
let accounts = gen_accounts(&[(1, &[0])]);
|
let accounts = gen_stakes(&[(1, &[0])]);
|
||||||
let epoch_stakes = EpochStakes::new_for_tests(2);
|
let epoch_stakes = EpochStakes::new_for_tests(2);
|
||||||
let locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
let locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
||||||
let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())]
|
let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())]
|
||||||
|
@ -411,8 +411,8 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collect_vote_lockouts_sums() {
|
fn test_collect_vote_lockouts_sums() {
|
||||||
//two accounts voting for slot 0 with 1 token staked
|
//two accounts voting for slot 0 with 1 token staked
|
||||||
let accounts = gen_accounts(&[(1, &[0]), (1, &[0])]);
|
let accounts = gen_stakes(&[(1, &[0]), (1, &[0])]);
|
||||||
let epoch_stakes = EpochStakes::new_from_stake_accounts(0, &accounts);
|
let epoch_stakes = EpochStakes::new_from_stakes(0, &accounts);
|
||||||
let locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
let locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
||||||
let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())]
|
let ancestors = vec![(1, vec![0].into_iter().collect()), (0, HashSet::new())]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -426,8 +426,8 @@ mod test {
|
||||||
fn test_collect_vote_lockouts_root() {
|
fn test_collect_vote_lockouts_root() {
|
||||||
let votes: Vec<u64> = (0..MAX_LOCKOUT_HISTORY as u64).into_iter().collect();
|
let votes: Vec<u64> = (0..MAX_LOCKOUT_HISTORY as u64).into_iter().collect();
|
||||||
//two accounts voting for slot 0 with 1 token staked
|
//two accounts voting for slot 0 with 1 token staked
|
||||||
let accounts = gen_accounts(&[(1, &votes), (1, &votes)]);
|
let accounts = gen_stakes(&[(1, &votes), (1, &votes)]);
|
||||||
let epoch_stakes = EpochStakes::new_from_stake_accounts(0, &accounts);
|
let epoch_stakes = EpochStakes::new_from_stakes(0, &accounts);
|
||||||
let mut locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
let mut locktower = Locktower::new(epoch_stakes, 0, 0.67);
|
||||||
let mut ancestors = HashMap::new();
|
let mut ancestors = HashMap::new();
|
||||||
for i in 0..(MAX_LOCKOUT_HISTORY + 1) {
|
for i in 0..(MAX_LOCKOUT_HISTORY + 1) {
|
||||||
|
@ -754,13 +754,13 @@ mod test {
|
||||||
let threshold_size = 0.67;
|
let threshold_size = 0.67;
|
||||||
let threshold_stake = (f64::ceil(total_stake as f64 * threshold_size)) as u64;
|
let threshold_stake = (f64::ceil(total_stake as f64 * threshold_size)) as u64;
|
||||||
let locktower_votes: Vec<u64> = (0..VOTE_THRESHOLD_DEPTH as u64).collect();
|
let locktower_votes: Vec<u64> = (0..VOTE_THRESHOLD_DEPTH as u64).collect();
|
||||||
let accounts = gen_accounts(&[
|
let accounts = gen_stakes(&[
|
||||||
(threshold_stake, &[(VOTE_THRESHOLD_DEPTH - 2) as u64]),
|
(threshold_stake, &[(VOTE_THRESHOLD_DEPTH - 2) as u64]),
|
||||||
(total_stake - threshold_stake, &locktower_votes[..]),
|
(total_stake - threshold_stake, &locktower_votes[..]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Initialize locktower
|
// Initialize locktower
|
||||||
let stakes: HashMap<_, _> = accounts.iter().map(|(pk, a)| (*pk, a.lamports)).collect();
|
let stakes: HashMap<_, _> = accounts.iter().map(|(pk, (s, _))| (*pk, *s)).collect();
|
||||||
let epoch_stakes = EpochStakes::new(0, stakes, &Pubkey::default());
|
let epoch_stakes = EpochStakes::new(0, stakes, &Pubkey::default());
|
||||||
let mut locktower = Locktower::new(epoch_stakes, VOTE_THRESHOLD_DEPTH, threshold_size);
|
let mut locktower = Locktower::new(epoch_stakes, VOTE_THRESHOLD_DEPTH, threshold_size);
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ pub fn get_supermajority_slot(bank: &Bank, epoch_height: u64) -> Option<u64> {
|
||||||
find_supermajority_slot(supermajority_stake, stakes_and_lockouts.iter())
|
find_supermajority_slot(supermajority_stake, stakes_and_lockouts.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vote_account_balances(bank: &Bank) -> HashMap<Pubkey, u64> {
|
pub fn vote_account_stakes(bank: &Bank) -> HashMap<Pubkey, u64> {
|
||||||
let node_staked_accounts = node_staked_accounts(bank);
|
let node_staked_accounts = node_staked_accounts(bank);
|
||||||
node_staked_accounts
|
node_staked_accounts
|
||||||
.map(|(id, stake, _)| (id, stake))
|
.map(|(id, (stake, _))| (id, stake))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +34,13 @@ pub fn delegated_stakes(bank: &Bank) -> HashMap<Pubkey, u64> {
|
||||||
|
|
||||||
/// At the specified epoch, collect the node account balance and vote states for nodes that
|
/// At the specified epoch, collect the node account balance and vote states for nodes that
|
||||||
/// have non-zero balance in their corresponding staking accounts
|
/// have non-zero balance in their corresponding staking accounts
|
||||||
pub fn vote_account_balances_at_epoch(
|
pub fn vote_account_stakes_at_epoch(
|
||||||
bank: &Bank,
|
bank: &Bank,
|
||||||
epoch_height: u64,
|
epoch_height: u64,
|
||||||
) -> Option<HashMap<Pubkey, u64>> {
|
) -> Option<HashMap<Pubkey, u64>> {
|
||||||
let node_staked_accounts = node_staked_accounts_at_epoch(bank, epoch_height);
|
let node_staked_accounts = node_staked_accounts_at_epoch(bank, epoch_height);
|
||||||
node_staked_accounts.map(|epoch_state| epoch_state.map(|(id, stake, _)| (*id, stake)).collect())
|
node_staked_accounts
|
||||||
|
.map(|epoch_state| epoch_state.map(|(id, (stake, _))| (*id, *stake)).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// At the specified epoch, collect the delegate account balance and vote states for delegates
|
/// At the specified epoch, collect the delegate account balance and vote states for delegates
|
||||||
|
@ -52,21 +53,18 @@ pub fn delegated_stakes_at_epoch(bank: &Bank, epoch_height: u64) -> Option<HashM
|
||||||
|
|
||||||
/// Collect the node account balance and vote states for nodes have non-zero balance in
|
/// Collect the node account balance and vote states for nodes have non-zero balance in
|
||||||
/// their corresponding staking accounts
|
/// their corresponding staking accounts
|
||||||
fn node_staked_accounts(bank: &Bank) -> impl Iterator<Item = (Pubkey, u64, Account)> {
|
fn node_staked_accounts(bank: &Bank) -> impl Iterator<Item = (Pubkey, (u64, Account))> {
|
||||||
bank.vote_accounts()
|
bank.vote_accounts().into_iter()
|
||||||
.into_iter()
|
|
||||||
.map(|(account_id, account)| (account_id, Bank::read_balance(&account), account))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_staked_accounts_at_epoch(
|
pub fn node_staked_accounts_at_epoch(
|
||||||
bank: &Bank,
|
bank: &Bank,
|
||||||
epoch_height: u64,
|
epoch_height: u64,
|
||||||
) -> Option<impl Iterator<Item = (&Pubkey, u64, &Account)>> {
|
) -> Option<impl Iterator<Item = (&Pubkey, &(u64, Account))>> {
|
||||||
bank.epoch_vote_accounts(epoch_height).map(|vote_accounts| {
|
bank.epoch_vote_accounts(epoch_height).map(|vote_accounts| {
|
||||||
vote_accounts
|
vote_accounts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(account_id, account)| filter_no_delegate(account_id, account))
|
.filter(|(account_id, (_, account))| filter_no_delegate(account_id, account))
|
||||||
.map(|(account_id, account)| (account_id, Bank::read_balance(&account), account))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +75,12 @@ fn filter_no_delegate(account_id: &Pubkey, account: &Account) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vote_state(
|
fn to_vote_state(
|
||||||
node_staked_accounts: impl Iterator<Item = (impl Borrow<Pubkey>, u64, impl Borrow<Account>)>,
|
node_staked_accounts: impl Iterator<Item = (impl Borrow<Pubkey>, impl Borrow<(u64, Account)>)>,
|
||||||
) -> impl Iterator<Item = (u64, VoteState)> {
|
) -> impl Iterator<Item = (u64, VoteState)> {
|
||||||
node_staked_accounts.filter_map(|(_, stake, account)| {
|
node_staked_accounts.filter_map(|(_, stake_account)| {
|
||||||
VoteState::deserialize(&account.borrow().data)
|
VoteState::deserialize(&stake_account.borrow().1.data)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|vote_state| (stake, vote_state))
|
.map(|vote_state| (stake_account.borrow().0, vote_state))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,17 +156,17 @@ pub mod tests {
|
||||||
|
|
||||||
// Epoch doesn't exist
|
// Epoch doesn't exist
|
||||||
let mut expected = HashMap::new();
|
let mut expected = HashMap::new();
|
||||||
assert_eq!(vote_account_balances_at_epoch(&bank, 10), None);
|
assert_eq!(vote_account_stakes_at_epoch(&bank, 10), None);
|
||||||
|
|
||||||
// First epoch has the bootstrap leader
|
// First epoch has the bootstrap leader
|
||||||
expected.insert(voting_keypair.pubkey(), BOOTSTRAP_LEADER_LAMPORTS);
|
expected.insert(voting_keypair.pubkey(), BOOTSTRAP_LEADER_LAMPORTS);
|
||||||
let expected = Some(expected);
|
let expected = Some(expected);
|
||||||
assert_eq!(vote_account_balances_at_epoch(&bank, 0), expected);
|
assert_eq!(vote_account_stakes_at_epoch(&bank, 0), expected);
|
||||||
|
|
||||||
// Second epoch carries same information
|
// Second epoch carries same information
|
||||||
let bank = new_from_parent(&Arc::new(bank), 1);
|
let bank = new_from_parent(&Arc::new(bank), 1);
|
||||||
assert_eq!(vote_account_balances_at_epoch(&bank, 0), expected);
|
assert_eq!(vote_account_stakes_at_epoch(&bank, 0), expected);
|
||||||
assert_eq!(vote_account_balances_at_epoch(&bank, 1), expected);
|
assert_eq!(vote_account_stakes_at_epoch(&bank, 1), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -33,13 +33,36 @@ use std::time::Instant;
|
||||||
/// cache of staking information
|
/// cache of staking information
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Stakes {
|
pub struct Stakes {
|
||||||
/// stakes
|
/// vote accounts
|
||||||
vote_accounts: HashMap<Pubkey, Account>,
|
pub vote_accounts: HashMap<Pubkey, (u64, Account)>,
|
||||||
|
|
||||||
/// stake_accounts
|
/// stake_accounts
|
||||||
stake_accounts: HashMap<Pubkey, Account>,
|
stake_accounts: HashMap<Pubkey, Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Stakes {
|
||||||
|
pub fn is_stake(account: &Account) -> bool {
|
||||||
|
solana_vote_api::check_id(&account.owner) || solana_stake_api::check_id(&account.owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, pubkey: &Pubkey, account: &Account) {
|
||||||
|
if solana_vote_api::check_id(&account.owner) {
|
||||||
|
if account.lamports != 0 {
|
||||||
|
self.vote_accounts
|
||||||
|
.insert(*pubkey, (account.lamports, account.clone()));
|
||||||
|
} else {
|
||||||
|
self.vote_accounts.remove(pubkey);
|
||||||
|
}
|
||||||
|
} else if solana_stake_api::check_id(&account.owner) {
|
||||||
|
if account.lamports != 0 {
|
||||||
|
self.stake_accounts.insert(*pubkey, account.clone());
|
||||||
|
} else {
|
||||||
|
self.stake_accounts.remove(pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type BankStatusCache = StatusCache<Result<()>>;
|
type BankStatusCache = StatusCache<Result<()>>;
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -126,10 +149,12 @@ impl Bank {
|
||||||
bank.process_genesis_block(genesis_block);
|
bank.process_genesis_block(genesis_block);
|
||||||
// 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 stakes = bank.stakes();
|
{
|
||||||
|
let stakes = bank.stakes.read().unwrap();
|
||||||
for i in 0..=bank.get_stakers_epoch(bank.slot) {
|
for i in 0..=bank.get_stakers_epoch(bank.slot) {
|
||||||
bank.epoch_stakes.insert(i, stakes.clone());
|
bank.epoch_stakes.insert(i, stakes.clone());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
bank
|
bank
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +171,7 @@ impl Bank {
|
||||||
|
|
||||||
bank.transaction_count
|
bank.transaction_count
|
||||||
.store(parent.transaction_count() as usize, Ordering::Relaxed);
|
.store(parent.transaction_count() as usize, Ordering::Relaxed);
|
||||||
bank.stakes = RwLock::new(parent.stakes());
|
bank.stakes = RwLock::new(parent.stakes.read().unwrap().clone());
|
||||||
|
|
||||||
bank.tick_height
|
bank.tick_height
|
||||||
.store(parent.tick_height.load(Ordering::SeqCst), Ordering::SeqCst);
|
.store(parent.tick_height.load(Ordering::SeqCst), Ordering::SeqCst);
|
||||||
|
@ -175,7 +200,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_stakes.get(&epoch).is_none() {
|
if epoch_stakes.get(&epoch).is_none() {
|
||||||
epoch_stakes.insert(epoch, bank.stakes());
|
epoch_stakes.insert(epoch, bank.stakes.read().unwrap().clone());
|
||||||
}
|
}
|
||||||
epoch_stakes
|
epoch_stakes
|
||||||
};
|
};
|
||||||
|
@ -284,6 +309,10 @@ impl Bank {
|
||||||
"solana_bpf_loader",
|
"solana_bpf_loader",
|
||||||
&solana_sdk::bpf_loader::id(),
|
&solana_sdk::bpf_loader::id(),
|
||||||
);
|
);
|
||||||
|
self.register_native_instruction_processor(
|
||||||
|
&solana_vote_program!().0,
|
||||||
|
&solana_vote_program!().1,
|
||||||
|
);
|
||||||
|
|
||||||
// Add additional native programs specified in the genesis block
|
// Add additional native programs specified in the genesis block
|
||||||
for (name, program_id) in &genesis_block.native_instruction_processors {
|
for (name, program_id) in &genesis_block.native_instruction_processors {
|
||||||
|
@ -772,33 +801,11 @@ impl Bank {
|
||||||
parents
|
parents
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_stakes_accounts(
|
|
||||||
accounts: &mut HashMap<Pubkey, Account>,
|
|
||||||
pubkey: &Pubkey,
|
|
||||||
account: &Account,
|
|
||||||
) {
|
|
||||||
if account.lamports != 0 {
|
|
||||||
accounts.insert(*pubkey, account.clone());
|
|
||||||
} else {
|
|
||||||
accounts.remove(pubkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, pubkey: &Pubkey, account: &Account) {
|
fn store(&self, pubkey: &Pubkey, account: &Account) {
|
||||||
self.accounts.store_slow(self.slot(), pubkey, account);
|
self.accounts.store_slow(self.slot(), pubkey, account);
|
||||||
|
|
||||||
if solana_vote_api::check_id(&account.owner) {
|
if Stakes::is_stake(account) {
|
||||||
Self::update_stakes_accounts(
|
self.stakes.write().unwrap().update(pubkey, account);
|
||||||
&mut self.stakes.write().unwrap().vote_accounts,
|
|
||||||
pubkey,
|
|
||||||
account,
|
|
||||||
);
|
|
||||||
} else if solana_stake_api::check_id(&account.owner) {
|
|
||||||
Self::update_stakes_accounts(
|
|
||||||
&mut self.stakes.write().unwrap().stake_accounts,
|
|
||||||
pubkey,
|
|
||||||
account,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,8 +923,6 @@ impl Bank {
|
||||||
res: &[Result<()>],
|
res: &[Result<()>],
|
||||||
loaded: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
loaded: &[Result<(InstructionAccounts, InstructionLoaders)>],
|
||||||
) {
|
) {
|
||||||
let mut stakes = self.stakes.write().unwrap();
|
|
||||||
|
|
||||||
for (i, raccs) in loaded.iter().enumerate() {
|
for (i, raccs) in loaded.iter().enumerate() {
|
||||||
if res[i].is_err() || raccs.is_err() {
|
if res[i].is_err() || raccs.is_err() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -926,33 +931,24 @@ impl Bank {
|
||||||
let message = &txs[i].message();
|
let message = &txs[i].message();
|
||||||
let acc = raccs.as_ref().unwrap();
|
let acc = raccs.as_ref().unwrap();
|
||||||
|
|
||||||
for (pubkey, account) in message.account_keys.iter().zip(acc.0.iter()) {
|
for (pubkey, account) in message
|
||||||
if solana_vote_api::check_id(&account.owner) {
|
.account_keys
|
||||||
Self::update_stakes_accounts(&mut stakes.vote_accounts, pubkey, account);
|
.iter()
|
||||||
} else if solana_stake_api::check_id(&account.owner) {
|
.zip(acc.0.iter())
|
||||||
Self::update_stakes_accounts(&mut stakes.stake_accounts, pubkey, account);
|
.filter(|(_, account)| Stakes::is_stake(account))
|
||||||
|
{
|
||||||
|
self.stakes.write().unwrap().update(pubkey, account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// current stakes for this bank
|
|
||||||
pub fn stakes(&self) -> Stakes {
|
|
||||||
self.stakes.read().unwrap().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// current vote accounts for this bank
|
/// current vote accounts for this bank
|
||||||
pub fn vote_accounts(&self) -> HashMap<Pubkey, Account> {
|
pub fn vote_accounts(&self) -> HashMap<Pubkey, (u64, Account)> {
|
||||||
self.stakes.read().unwrap().vote_accounts.clone()
|
self.stakes.read().unwrap().vote_accounts.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stakes for the specific epoch
|
|
||||||
pub fn epoch_stakes(&self, epoch: u64) -> Option<&Stakes> {
|
|
||||||
self.epoch_stakes.get(&epoch)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// vote accounts for the specific epoch
|
/// vote accounts for the specific epoch
|
||||||
pub fn epoch_vote_accounts(&self, epoch: u64) -> Option<&HashMap<Pubkey, Account>> {
|
pub fn epoch_vote_accounts(&self, epoch: u64) -> Option<&HashMap<Pubkey, (u64, Account)>> {
|
||||||
self.epoch_stakes
|
self.epoch_stakes
|
||||||
.get(&epoch)
|
.get(&epoch)
|
||||||
.map(|stakes| &stakes.vote_accounts)
|
.map(|stakes| &stakes.vote_accounts)
|
||||||
|
@ -1583,13 +1579,13 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_epoch_stakes() {
|
fn test_bank_epoch_vote_accounts() {
|
||||||
let leader_id = Pubkey::new_rand();
|
let leader_id = Pubkey::new_rand();
|
||||||
let leader_lamports = 3;
|
let leader_lamports = 3;
|
||||||
let mut genesis_block = create_genesis_block_with_leader(5, &leader_id, leader_lamports).0;
|
let mut genesis_block = create_genesis_block_with_leader(5, &leader_id, leader_lamports).0;
|
||||||
|
|
||||||
// set this up weird, forces future generation, odd mod(), etc.
|
// set this up weird, forces future generation, odd mod(), etc.
|
||||||
// this says: "stakes for epoch X should be generated at slot index 3 in epoch X-2...
|
// this says: "vote_accounts for epoch X should be generated at slot index 3 in epoch X-2...
|
||||||
const SLOTS_PER_EPOCH: u64 = MINIMUM_SLOT_LENGTH as u64;
|
const SLOTS_PER_EPOCH: u64 = MINIMUM_SLOT_LENGTH as u64;
|
||||||
const STAKERS_SLOT_OFFSET: u64 = SLOTS_PER_EPOCH * 3 - 3;
|
const STAKERS_SLOT_OFFSET: u64 = SLOTS_PER_EPOCH * 3 - 3;
|
||||||
genesis_block.slots_per_epoch = SLOTS_PER_EPOCH;
|
genesis_block.slots_per_epoch = SLOTS_PER_EPOCH;
|
||||||
|
@ -1598,10 +1594,10 @@ mod tests {
|
||||||
|
|
||||||
let parent = Arc::new(Bank::new(&genesis_block));
|
let parent = Arc::new(Bank::new(&genesis_block));
|
||||||
|
|
||||||
let stakes0: Option<HashMap<_, _>> = parent.epoch_vote_accounts(0).map(|accounts| {
|
let vote_accounts0: Option<HashMap<_, _>> = parent.epoch_vote_accounts(0).map(|accounts| {
|
||||||
accounts
|
accounts
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pubkey, account)| {
|
.filter_map(|(pubkey, (_, account))| {
|
||||||
if let Ok(vote_state) = VoteState::deserialize(&account.data) {
|
if let Ok(vote_state) = VoteState::deserialize(&account.data) {
|
||||||
if vote_state.node_id == leader_id {
|
if vote_state.node_id == leader_id {
|
||||||
Some((*pubkey, true))
|
Some((*pubkey, true))
|
||||||
|
@ -1614,15 +1610,15 @@ mod tests {
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
assert!(stakes0.is_some());
|
assert!(vote_accounts0.is_some());
|
||||||
assert!(stakes0.iter().len() != 0);
|
assert!(vote_accounts0.iter().len() != 0);
|
||||||
|
|
||||||
let mut i = 1;
|
let mut i = 1;
|
||||||
loop {
|
loop {
|
||||||
if i > STAKERS_SLOT_OFFSET / SLOTS_PER_EPOCH {
|
if i > STAKERS_SLOT_OFFSET / SLOTS_PER_EPOCH {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert!(parent.epoch_stakes(i).is_some());
|
assert!(parent.epoch_vote_accounts(i).is_some());
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1633,7 +1629,7 @@ mod tests {
|
||||||
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH),
|
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(child.epoch_stakes(i).is_some());
|
assert!(child.epoch_vote_accounts(i).is_some());
|
||||||
|
|
||||||
// child crosses epoch boundary but isn't the first slot in the epoch
|
// child crosses epoch boundary but isn't the first slot in the epoch
|
||||||
let child = Bank::new_from_parent(
|
let child = Bank::new_from_parent(
|
||||||
|
@ -1641,7 +1637,7 @@ mod tests {
|
||||||
&leader_id,
|
&leader_id,
|
||||||
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1,
|
SLOTS_PER_EPOCH - (STAKERS_SLOT_OFFSET % SLOTS_PER_EPOCH) + 1,
|
||||||
);
|
);
|
||||||
assert!(child.epoch_stakes(i).is_some());
|
assert!(child.epoch_vote_accounts(i).is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue