2019-05-16 08:23:31 -07:00
|
|
|
//! Stakes serve as a cache of stake and vote accounts to derive
|
|
|
|
//! node stakes
|
2021-08-10 05:59:12 -07:00
|
|
|
use {
|
2021-12-03 06:54:38 -08:00
|
|
|
crate::{
|
2022-04-15 07:17:13 -07:00
|
|
|
stake_account,
|
2021-12-03 10:10:29 -08:00
|
|
|
stake_history::StakeHistory,
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
vote_account::{VoteAccount, VoteAccounts},
|
2021-12-03 06:54:38 -08:00
|
|
|
},
|
2021-12-10 07:51:33 -08:00
|
|
|
dashmap::DashMap,
|
2022-03-16 05:58:05 -07:00
|
|
|
im::HashMap as ImHashMap,
|
2022-08-22 06:38:41 -07:00
|
|
|
log::error,
|
2021-12-10 07:51:33 -08:00
|
|
|
num_derive::ToPrimitive,
|
|
|
|
num_traits::ToPrimitive,
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
rayon::{prelude::*, ThreadPool},
|
2021-08-10 05:59:12 -07:00
|
|
|
solana_sdk::{
|
|
|
|
account::{AccountSharedData, ReadableAccount},
|
2021-12-10 07:51:33 -08:00
|
|
|
clock::{Epoch, Slot},
|
2021-08-10 05:59:12 -07:00
|
|
|
pubkey::Pubkey,
|
2022-04-08 06:45:26 -07:00
|
|
|
stake::state::{Delegation, StakeActivationStatus},
|
2021-06-15 09:04:00 -07:00
|
|
|
},
|
2021-08-10 05:59:12 -07:00
|
|
|
solana_vote_program::vote_state::VoteState,
|
2021-12-10 07:51:33 -08:00
|
|
|
std::{
|
2022-08-22 06:38:41 -07:00
|
|
|
collections::{HashMap, HashSet},
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
ops::Add,
|
2021-12-10 07:51:33 -08:00
|
|
|
sync::{Arc, RwLock, RwLockReadGuard},
|
|
|
|
},
|
2022-04-08 06:45:26 -07:00
|
|
|
thiserror::Error,
|
2020-01-28 17:03:20 -08:00
|
|
|
};
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
#[derive(Debug, Error)]
|
2022-04-11 14:07:52 -07:00
|
|
|
pub enum Error {
|
2022-04-08 06:45:26 -07:00
|
|
|
#[error("Invalid delegation: {0}")]
|
|
|
|
InvalidDelegation(Pubkey),
|
|
|
|
#[error(transparent)]
|
|
|
|
InvalidStakeAccount(#[from] stake_account::Error),
|
|
|
|
#[error("Stake account not found: {0}")]
|
|
|
|
StakeAccountNotFound(Pubkey),
|
2022-08-22 06:38:41 -07:00
|
|
|
#[error("Vote account mismatch: {0}")]
|
|
|
|
VoteAccountMismatch(Pubkey),
|
|
|
|
#[error("Vote account not cached: {0}")]
|
|
|
|
VoteAccountNotCached(Pubkey),
|
|
|
|
#[error("Vote account not found: {0}")]
|
|
|
|
VoteAccountNotFound(Pubkey),
|
2022-04-08 06:45:26 -07:00
|
|
|
}
|
|
|
|
|
2022-05-22 18:00:42 -07:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, ToPrimitive)]
|
2021-12-10 07:51:33 -08:00
|
|
|
pub enum InvalidCacheEntryReason {
|
|
|
|
Missing,
|
|
|
|
BadState,
|
|
|
|
WrongOwner,
|
|
|
|
}
|
|
|
|
|
2022-04-15 07:17:13 -07:00
|
|
|
type StakeAccount = stake_account::StakeAccount<Delegation>;
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
#[derive(Default, Debug, AbiExample)]
|
|
|
|
pub(crate) struct StakesCache(RwLock<Stakes<StakeAccount>>);
|
2021-12-10 07:51:33 -08:00
|
|
|
|
|
|
|
impl StakesCache {
|
2022-04-08 06:45:26 -07:00
|
|
|
pub(crate) fn new(stakes: Stakes<StakeAccount>) -> Self {
|
2021-12-10 07:51:33 -08:00
|
|
|
Self(RwLock::new(stakes))
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
pub(crate) fn stakes(&self) -> RwLockReadGuard<Stakes<StakeAccount>> {
|
2021-12-10 07:51:33 -08:00
|
|
|
self.0.read().unwrap()
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn check_and_store(&self, pubkey: &Pubkey, account: &impl ReadableAccount) {
|
2022-04-08 06:45:55 -07:00
|
|
|
// TODO: If the account is already cached as a vote or stake account
|
|
|
|
// but the owner changes, then this needs to evict the account from
|
|
|
|
// the cache. see:
|
|
|
|
// https://github.com/solana-labs/solana/pull/24200#discussion_r849935444
|
2022-05-06 07:04:49 -07:00
|
|
|
let owner = account.owner();
|
|
|
|
// Zero lamport accounts are not stored in accounts-db
|
|
|
|
// and so should be removed from cache as well.
|
|
|
|
if account.lamports() == 0 {
|
|
|
|
if solana_vote_program::check_id(owner) {
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.remove_vote_account(pubkey);
|
|
|
|
} else if solana_stake_program::check_id(owner) {
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.remove_stake_delegation(pubkey);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
debug_assert_ne!(account.lamports(), 0u64);
|
|
|
|
if solana_vote_program::check_id(owner) {
|
|
|
|
if VoteState::is_correct_size_and_initialized(account.data()) {
|
2022-06-22 19:11:01 -07:00
|
|
|
match VoteAccount::try_from(account.to_account_shared_data()) {
|
2022-05-06 09:22:49 -07:00
|
|
|
Ok(vote_account) => {
|
|
|
|
{
|
|
|
|
// Called to eagerly deserialize vote state
|
|
|
|
let _res = vote_account.vote_state();
|
|
|
|
}
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.upsert_vote_account(pubkey, vote_account);
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.remove_vote_account(pubkey)
|
|
|
|
}
|
2021-12-10 13:02:35 -08:00
|
|
|
}
|
|
|
|
} else {
|
2022-05-06 07:04:49 -07:00
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.remove_vote_account(pubkey)
|
2021-12-10 13:02:35 -08:00
|
|
|
};
|
2022-05-06 07:04:49 -07:00
|
|
|
} else if solana_stake_program::check_id(owner) {
|
2022-06-22 19:11:01 -07:00
|
|
|
match StakeAccount::try_from(account.to_account_shared_data()) {
|
2022-05-06 07:04:49 -07:00
|
|
|
Ok(stake_account) => {
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.upsert_stake_delegation(*pubkey, stake_account);
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.remove_stake_delegation(pubkey);
|
|
|
|
}
|
|
|
|
}
|
2021-12-10 07:51:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn activate_epoch(&self, next_epoch: Epoch, thread_pool: &ThreadPool) {
|
2021-12-10 07:51:33 -08:00
|
|
|
let mut stakes = self.0.write().unwrap();
|
|
|
|
stakes.activate_epoch(next_epoch, thread_pool)
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn handle_invalid_keys(
|
2021-12-10 07:51:33 -08:00
|
|
|
&self,
|
|
|
|
invalid_stake_keys: DashMap<Pubkey, InvalidCacheEntryReason>,
|
|
|
|
invalid_vote_keys: DashMap<Pubkey, InvalidCacheEntryReason>,
|
|
|
|
current_slot: Slot,
|
|
|
|
) {
|
|
|
|
if invalid_stake_keys.is_empty() && invalid_vote_keys.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prune invalid stake delegations and vote accounts that were
|
|
|
|
// not properly evicted in normal operation.
|
2022-06-02 14:04:54 -07:00
|
|
|
let mut stakes = self.0.write().unwrap();
|
2021-12-10 07:51:33 -08:00
|
|
|
|
|
|
|
for (stake_pubkey, reason) in invalid_stake_keys {
|
2022-06-02 14:04:54 -07:00
|
|
|
stakes.remove_stake_delegation(&stake_pubkey);
|
2021-12-10 07:51:33 -08:00
|
|
|
datapoint_warn!(
|
|
|
|
"bank-stake_delegation_accounts-invalid-account",
|
|
|
|
("slot", current_slot as i64, i64),
|
|
|
|
("stake-address", format!("{:?}", stake_pubkey), String),
|
|
|
|
("reason", reason.to_i64().unwrap_or_default(), i64),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (vote_pubkey, reason) in invalid_vote_keys {
|
2022-06-02 14:04:54 -07:00
|
|
|
stakes.remove_vote_account(&vote_pubkey);
|
2021-12-10 07:51:33 -08:00
|
|
|
datapoint_warn!(
|
|
|
|
"bank-stake_delegation_accounts-invalid-account",
|
|
|
|
("slot", current_slot as i64, i64),
|
|
|
|
("vote-address", format!("{:?}", vote_pubkey), String),
|
|
|
|
("reason", reason.to_i64().unwrap_or_default(), i64),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
/// The generic type T is either Delegation or StakeAccount.
|
|
|
|
/// Stake<Delegation> is equivalent to the old code and is used for backward
|
|
|
|
/// compatibility in BankFieldsToDeserialize.
|
|
|
|
/// But banks cache Stakes<StakeAccount> which includes the entire stake
|
|
|
|
/// account and StakeState deserialized from the account. Doing so, will remove
|
|
|
|
/// the need to load the stake account from accounts-db when working with
|
|
|
|
/// stake-delegations.
|
2020-07-06 04:22:23 -07:00
|
|
|
#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize, AbiExample)]
|
2022-04-08 06:45:26 -07:00
|
|
|
pub struct Stakes<T: Clone> {
|
2019-05-16 08:23:31 -07:00
|
|
|
/// vote accounts
|
2020-12-17 13:22:50 -08:00
|
|
|
vote_accounts: VoteAccounts,
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-11-25 13:14:32 -08:00
|
|
|
/// stake_delegations
|
2022-04-08 06:45:26 -07:00
|
|
|
stake_delegations: ImHashMap<Pubkey, T>,
|
2019-06-14 11:38:37 -07:00
|
|
|
|
2020-07-20 21:57:25 -07:00
|
|
|
/// unused
|
|
|
|
unused: u64,
|
2019-06-19 11:54:52 -07:00
|
|
|
|
|
|
|
/// current epoch, used to calculate current stake
|
2019-07-31 15:13:26 -07:00
|
|
|
epoch: Epoch,
|
2019-08-12 20:59:57 -07:00
|
|
|
|
|
|
|
/// history of staking levels
|
|
|
|
stake_history: StakeHistory,
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
|
2022-04-11 14:07:52 -07:00
|
|
|
// For backward compatibility, we can only serialize and deserialize
|
|
|
|
// Stakes<Delegation>. However Bank caches Stakes<StakeAccount>. This type
|
|
|
|
// mismatch incurs a conversion cost at epoch boundary when updating
|
|
|
|
// EpochStakes.
|
|
|
|
// Below type allows EpochStakes to include either a Stakes<StakeAccount> or
|
|
|
|
// Stakes<Delegation> and so bypass the conversion cost between the two at the
|
|
|
|
// epoch boundary.
|
|
|
|
#[derive(Debug, AbiExample)]
|
|
|
|
pub enum StakesEnum {
|
|
|
|
Accounts(Stakes<StakeAccount>),
|
|
|
|
Delegations(Stakes<Delegation>),
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
impl<T: Clone> Stakes<T> {
|
|
|
|
pub fn vote_accounts(&self) -> &VoteAccounts {
|
|
|
|
&self.vote_accounts
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
|
|
|
|
self.vote_accounts.staked_nodes()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stakes<StakeAccount> {
|
|
|
|
/// Creates a Stake<StakeAccount> from Stake<Delegation> by loading the
|
|
|
|
/// full account state for respective stake pubkeys. get_account function
|
|
|
|
/// should return the account at the respective slot where stakes where
|
|
|
|
/// cached.
|
|
|
|
pub(crate) fn new<F>(stakes: &Stakes<Delegation>, get_account: F) -> Result<Self, Error>
|
|
|
|
where
|
|
|
|
F: Fn(&Pubkey) -> Option<AccountSharedData>,
|
|
|
|
{
|
|
|
|
let stake_delegations = stakes.stake_delegations.iter().map(|(pubkey, delegation)| {
|
|
|
|
let stake_account = match get_account(pubkey) {
|
|
|
|
None => return Err(Error::StakeAccountNotFound(*pubkey)),
|
|
|
|
Some(account) => account,
|
|
|
|
};
|
|
|
|
let stake_account = StakeAccount::try_from(stake_account)?;
|
|
|
|
// Sanity check that the delegation is consistent with what is
|
|
|
|
// stored in the account.
|
2022-04-15 07:17:13 -07:00
|
|
|
if stake_account.delegation() == *delegation {
|
2022-04-08 06:45:26 -07:00
|
|
|
Ok((*pubkey, stake_account))
|
|
|
|
} else {
|
|
|
|
Err(Error::InvalidDelegation(*pubkey))
|
|
|
|
}
|
|
|
|
});
|
2022-08-22 06:38:41 -07:00
|
|
|
// Assert that cached vote accounts are consistent with accounts-db.
|
|
|
|
for (pubkey, vote_account) in stakes.vote_accounts.iter() {
|
|
|
|
let account = match get_account(pubkey) {
|
|
|
|
None => return Err(Error::VoteAccountNotFound(*pubkey)),
|
|
|
|
Some(account) => account,
|
|
|
|
};
|
|
|
|
// Ignoring rent_epoch until the feature for
|
|
|
|
// preserve_rent_epoch_for_rent_exempt_accounts is activated.
|
|
|
|
let vote_account = vote_account.account();
|
|
|
|
if vote_account.lamports() != account.lamports()
|
|
|
|
|| vote_account.owner() != account.owner()
|
|
|
|
|| vote_account.executable() != account.executable()
|
|
|
|
|| vote_account.data() != account.data()
|
|
|
|
{
|
|
|
|
error!(
|
|
|
|
"vote account mismatch: {}, {:?}, {:?}",
|
|
|
|
pubkey, vote_account, account
|
|
|
|
);
|
|
|
|
return Err(Error::VoteAccountMismatch(*pubkey));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Assert that all valid vote-accounts referenced in
|
|
|
|
// stake delegations are already cached.
|
|
|
|
let voter_pubkeys: HashSet<Pubkey> = stakes
|
|
|
|
.stake_delegations
|
|
|
|
.values()
|
|
|
|
.map(|delegation| delegation.voter_pubkey)
|
|
|
|
.filter(|voter_pubkey| stakes.vote_accounts.get(voter_pubkey).is_none())
|
|
|
|
.collect();
|
|
|
|
for pubkey in voter_pubkeys {
|
|
|
|
let account = match get_account(&pubkey) {
|
|
|
|
None => continue,
|
|
|
|
Some(account) => account,
|
|
|
|
};
|
|
|
|
if VoteState::is_correct_size_and_initialized(account.data())
|
|
|
|
&& VoteAccount::try_from(account.clone()).is_ok()
|
|
|
|
{
|
|
|
|
error!("vote account not cached: {}, {:?}", pubkey, account);
|
|
|
|
return Err(Error::VoteAccountNotCached(pubkey));
|
|
|
|
}
|
|
|
|
}
|
2022-04-08 06:45:26 -07:00
|
|
|
Ok(Self {
|
|
|
|
vote_accounts: stakes.vote_accounts.clone(),
|
|
|
|
stake_delegations: stake_delegations.collect::<Result<_, _>>()?,
|
|
|
|
unused: stakes.unused,
|
|
|
|
epoch: stakes.epoch,
|
|
|
|
stake_history: stakes.stake_history.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn history(&self) -> &StakeHistory {
|
2019-08-12 20:59:57 -07:00
|
|
|
&self.stake_history
|
|
|
|
}
|
2021-10-05 21:53:26 -07:00
|
|
|
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
fn activate_epoch(&mut self, next_epoch: Epoch, thread_pool: &ThreadPool) {
|
|
|
|
type StakesHashMap = HashMap</*voter:*/ Pubkey, /*stake:*/ u64>;
|
|
|
|
fn merge(mut acc: StakesHashMap, other: StakesHashMap) -> StakesHashMap {
|
|
|
|
if acc.len() < other.len() {
|
|
|
|
return merge(other, acc);
|
2021-10-05 21:53:26 -07:00
|
|
|
}
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
for (key, stake) in other {
|
|
|
|
*acc.entry(key).or_default() += stake;
|
|
|
|
}
|
|
|
|
acc
|
|
|
|
}
|
|
|
|
let stake_delegations: Vec<_> = self.stake_delegations.values().collect();
|
|
|
|
// Wrap up the prev epoch by adding new stake history entry for the
|
|
|
|
// prev epoch.
|
|
|
|
let stake_history_entry = thread_pool.install(|| {
|
|
|
|
stake_delegations
|
2021-10-05 21:53:26 -07:00
|
|
|
.par_iter()
|
2022-04-08 06:45:26 -07:00
|
|
|
.fold(StakeActivationStatus::default, |acc, stake_account| {
|
2022-04-15 07:17:13 -07:00
|
|
|
let delegation = stake_account.delegation();
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
acc + delegation
|
|
|
|
.stake_activating_and_deactivating(self.epoch, Some(&self.stake_history))
|
2021-10-05 21:53:26 -07:00
|
|
|
})
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
.reduce(StakeActivationStatus::default, Add::add)
|
|
|
|
});
|
|
|
|
self.stake_history.add(self.epoch, stake_history_entry);
|
|
|
|
self.epoch = next_epoch;
|
|
|
|
// Refresh the stake distribution of vote accounts for the next epoch,
|
|
|
|
// using new stake history.
|
|
|
|
let delegated_stakes = thread_pool.install(|| {
|
|
|
|
stake_delegations
|
|
|
|
.par_iter()
|
2022-04-08 06:45:26 -07:00
|
|
|
.fold(HashMap::default, |mut delegated_stakes, stake_account| {
|
2022-04-15 07:17:13 -07:00
|
|
|
let delegation = stake_account.delegation();
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
let entry = delegated_stakes.entry(delegation.voter_pubkey).or_default();
|
|
|
|
*entry += delegation.stake(self.epoch, Some(&self.stake_history));
|
|
|
|
delegated_stakes
|
|
|
|
})
|
|
|
|
.reduce(HashMap::default, merge)
|
2021-10-05 21:53:26 -07:00
|
|
|
});
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
self.vote_accounts = self
|
|
|
|
.vote_accounts
|
|
|
|
.iter()
|
2022-06-25 13:03:15 -07:00
|
|
|
.map(|(&vote_pubkey, vote_account)| {
|
improves Stakes::activate_epoch performance (#24068)
Tested with mainnet stakes obtained from the ledger at 5 recent epoch
boundaries, this code is ~30% faster than current master.
Current code:
epoch: 289, elapsed: 82901us
epoch: 290, elapsed: 80525us
epoch: 291, elapsed: 79122us
epoch: 292, elapsed: 79961us
epoch: 293, elapsed: 78965us
This commit:
epoch: 289, elapsed: 61710us
epoch: 290, elapsed: 55721us
epoch: 291, elapsed: 55886us
epoch: 292, elapsed: 55399us
epoch: 293, elapsed: 56803us
2022-04-02 15:48:51 -07:00
|
|
|
let delegated_stake = delegated_stakes
|
|
|
|
.get(&vote_pubkey)
|
|
|
|
.copied()
|
|
|
|
.unwrap_or_default();
|
|
|
|
(vote_pubkey, (delegated_stake, vote_account.clone()))
|
|
|
|
})
|
|
|
|
.collect();
|
2021-10-05 21:53:26 -07:00
|
|
|
}
|
|
|
|
|
2021-12-01 08:29:24 -08:00
|
|
|
/// Sum the stakes that point to the given voter_pubkey
|
2019-08-12 20:59:57 -07:00
|
|
|
fn calculate_stake(
|
|
|
|
&self,
|
|
|
|
voter_pubkey: &Pubkey,
|
|
|
|
epoch: Epoch,
|
2021-12-02 12:19:22 -08:00
|
|
|
stake_history: &StakeHistory,
|
2019-08-12 20:59:57 -07:00
|
|
|
) -> u64 {
|
2019-11-25 13:14:32 -08:00
|
|
|
self.stake_delegations
|
2022-04-08 06:45:26 -07:00
|
|
|
.values()
|
2022-04-15 07:17:13 -07:00
|
|
|
.map(StakeAccount::delegation)
|
2022-04-08 06:45:26 -07:00
|
|
|
.filter(|delegation| &delegation.voter_pubkey == voter_pubkey)
|
|
|
|
.map(|delegation| delegation.stake(epoch, Some(stake_history)))
|
2019-05-16 08:23:31 -07:00
|
|
|
.sum()
|
|
|
|
}
|
|
|
|
|
2021-12-01 08:29:24 -08:00
|
|
|
/// Sum the lamports of the vote accounts and the delegated stake
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn vote_balance_and_staked(&self) -> u64 {
|
2022-04-15 07:17:13 -07:00
|
|
|
let get_stake = |stake_account: &StakeAccount| stake_account.delegation().stake;
|
2022-06-25 13:03:15 -07:00
|
|
|
let get_lamports = |(_, vote_account): (_, &VoteAccount)| vote_account.lamports();
|
2021-12-01 08:29:24 -08:00
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
self.stake_delegations.values().map(get_stake).sum::<u64>()
|
2021-12-01 08:29:24 -08:00
|
|
|
+ self.vote_accounts.iter().map(get_lamports).sum::<u64>()
|
2020-07-20 21:57:25 -07:00
|
|
|
}
|
|
|
|
|
2022-05-06 07:04:49 -07:00
|
|
|
fn remove_vote_account(&mut self, vote_pubkey: &Pubkey) {
|
2021-12-09 11:12:11 -08:00
|
|
|
self.vote_accounts.remove(vote_pubkey);
|
|
|
|
}
|
|
|
|
|
2022-05-06 07:04:49 -07:00
|
|
|
fn remove_stake_delegation(&mut self, stake_pubkey: &Pubkey) {
|
2022-04-08 06:45:26 -07:00
|
|
|
if let Some(stake_account) = self.stake_delegations.remove(stake_pubkey) {
|
2022-04-15 07:17:13 -07:00
|
|
|
let removed_delegation = stake_account.delegation();
|
2021-12-09 11:12:11 -08:00
|
|
|
let removed_stake = removed_delegation.stake(self.epoch, Some(&self.stake_history));
|
|
|
|
self.vote_accounts
|
|
|
|
.sub_stake(&removed_delegation.voter_pubkey, removed_stake);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-06 07:04:49 -07:00
|
|
|
fn upsert_vote_account(&mut self, vote_pubkey: &Pubkey, vote_account: VoteAccount) {
|
|
|
|
debug_assert_ne!(vote_account.lamports(), 0u64);
|
|
|
|
debug_assert!(vote_account.is_deserialized());
|
2021-12-10 13:02:35 -08:00
|
|
|
// unconditionally remove existing at first; there is no dependent calculated state for
|
|
|
|
// votes, not like stakes (stake codepath maintains calculated stake value grouped by
|
|
|
|
// delegated vote pubkey)
|
2022-05-06 07:04:49 -07:00
|
|
|
let stake = match self.vote_accounts.remove(vote_pubkey) {
|
|
|
|
None => self.calculate_stake(vote_pubkey, self.epoch, &self.stake_history),
|
|
|
|
Some((stake, _)) => stake,
|
|
|
|
};
|
|
|
|
let entry = (stake, vote_account);
|
|
|
|
self.vote_accounts.insert(*vote_pubkey, entry);
|
2021-12-10 13:02:35 -08:00
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2022-05-06 07:04:49 -07:00
|
|
|
fn upsert_stake_delegation(&mut self, stake_pubkey: Pubkey, stake_account: StakeAccount) {
|
|
|
|
debug_assert_ne!(stake_account.lamports(), 0u64);
|
|
|
|
let delegation = stake_account.delegation();
|
|
|
|
let voter_pubkey = delegation.voter_pubkey;
|
|
|
|
let stake = delegation.stake(self.epoch, Some(&self.stake_history));
|
|
|
|
match self.stake_delegations.insert(stake_pubkey, stake_account) {
|
|
|
|
None => self.vote_accounts.add_stake(&voter_pubkey, stake),
|
|
|
|
Some(old_stake_account) => {
|
|
|
|
let old_delegation = old_stake_account.delegation();
|
|
|
|
let old_voter_pubkey = old_delegation.voter_pubkey;
|
|
|
|
let old_stake = old_delegation.stake(self.epoch, Some(&self.stake_history));
|
|
|
|
if voter_pubkey != old_voter_pubkey || stake != old_stake {
|
|
|
|
self.vote_accounts.sub_stake(&old_voter_pubkey, old_stake);
|
|
|
|
self.vote_accounts.add_stake(&voter_pubkey, stake);
|
|
|
|
}
|
2021-12-10 13:02:35 -08:00
|
|
|
}
|
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
2019-09-30 18:57:49 -07:00
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
pub(crate) fn stake_delegations(&self) -> &ImHashMap<Pubkey, StakeAccount> {
|
2019-12-08 20:52:01 -08:00
|
|
|
&self.stake_delegations
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
pub(crate) fn highest_staked_node(&self) -> Option<Pubkey> {
|
2022-06-25 13:03:15 -07:00
|
|
|
let vote_account = self.vote_accounts.find_max_by_delegated_stake()?;
|
2022-06-27 07:09:06 -07:00
|
|
|
vote_account.node_pubkey()
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
2022-04-08 06:45:26 -07:00
|
|
|
}
|
2020-12-17 13:22:50 -08:00
|
|
|
|
2022-04-11 14:07:52 -07:00
|
|
|
impl StakesEnum {
|
|
|
|
pub fn vote_accounts(&self) -> &VoteAccounts {
|
|
|
|
match self {
|
|
|
|
StakesEnum::Accounts(stakes) => stakes.vote_accounts(),
|
|
|
|
StakesEnum::Delegations(stakes) => stakes.vote_accounts(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
|
|
|
|
match self {
|
|
|
|
StakesEnum::Accounts(stakes) => stakes.staked_nodes(),
|
|
|
|
StakesEnum::Delegations(stakes) => stakes.staked_nodes(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-15 07:17:13 -07:00
|
|
|
impl From<Stakes<StakeAccount>> for Stakes<Delegation> {
|
|
|
|
fn from(stakes: Stakes<StakeAccount>) -> Self {
|
2022-04-08 06:45:26 -07:00
|
|
|
let stake_delegations = stakes
|
|
|
|
.stake_delegations
|
|
|
|
.into_iter()
|
2022-04-15 07:17:13 -07:00
|
|
|
.map(|(pubkey, stake_account)| (pubkey, stake_account.delegation()))
|
|
|
|
.collect();
|
|
|
|
Self {
|
2022-04-08 06:45:26 -07:00
|
|
|
vote_accounts: stakes.vote_accounts,
|
|
|
|
stake_delegations,
|
|
|
|
unused: stakes.unused,
|
|
|
|
epoch: stakes.epoch,
|
|
|
|
stake_history: stakes.stake_history,
|
2022-04-15 07:17:13 -07:00
|
|
|
}
|
2019-06-11 11:44:58 -07:00
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
|
2022-04-11 14:07:52 -07:00
|
|
|
impl From<Stakes<StakeAccount>> for StakesEnum {
|
|
|
|
fn from(stakes: Stakes<StakeAccount>) -> Self {
|
|
|
|
Self::Accounts(stakes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Stakes<Delegation>> for StakesEnum {
|
|
|
|
fn from(stakes: Stakes<Delegation>) -> Self {
|
|
|
|
Self::Delegations(stakes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Two StakesEnums are equal as long as they represent the same delegations;
|
|
|
|
// whether these delegations are stored as StakeAccounts or Delegations.
|
|
|
|
// Therefore, if one side is Stakes<StakeAccount> and the other is a
|
|
|
|
// Stakes<Delegation> we convert the former one to Stakes<Delegation> before
|
|
|
|
// comparing for equality.
|
|
|
|
impl PartialEq<StakesEnum> for StakesEnum {
|
|
|
|
fn eq(&self, other: &StakesEnum) -> bool {
|
|
|
|
match (self, other) {
|
|
|
|
(Self::Accounts(stakes), Self::Accounts(other)) => stakes == other,
|
|
|
|
(Self::Accounts(stakes), Self::Delegations(other)) => {
|
2022-04-15 07:17:13 -07:00
|
|
|
let stakes = Stakes::<Delegation>::from(stakes.clone());
|
|
|
|
&stakes == other
|
2022-04-11 14:07:52 -07:00
|
|
|
}
|
|
|
|
(Self::Delegations(stakes), Self::Accounts(other)) => {
|
2022-04-15 07:17:13 -07:00
|
|
|
let other = Stakes::<Delegation>::from(other.clone());
|
|
|
|
stakes == &other
|
2022-04-11 14:07:52 -07:00
|
|
|
}
|
|
|
|
(Self::Delegations(stakes), Self::Delegations(other)) => stakes == other,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// In order to maintain backward compatibility, the StakesEnum in EpochStakes
|
|
|
|
// and SerializableVersionedBank should be serialized as Stakes<Delegation>.
|
|
|
|
pub(crate) mod serde_stakes_enum_compat {
|
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
serde::{Deserialize, Deserializer, Serialize, Serializer},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub(crate) fn serialize<S>(stakes: &StakesEnum, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
match stakes {
|
|
|
|
StakesEnum::Accounts(stakes) => {
|
2022-04-15 07:17:13 -07:00
|
|
|
let stakes = Stakes::<Delegation>::from(stakes.clone());
|
2022-04-11 14:07:52 -07:00
|
|
|
stakes.serialize(serializer)
|
|
|
|
}
|
|
|
|
StakesEnum::Delegations(stakes) => stakes.serialize(serializer),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Arc<StakesEnum>, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
let stakes = Stakes::<Delegation>::deserialize(deserializer)?;
|
|
|
|
Ok(Arc::new(StakesEnum::Delegations(stakes)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 08:23:31 -07:00
|
|
|
#[cfg(test)]
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
2022-04-11 14:07:52 -07:00
|
|
|
rand::Rng,
|
2021-12-03 09:00:31 -08:00
|
|
|
rayon::ThreadPoolBuilder,
|
2022-04-08 06:45:26 -07:00
|
|
|
solana_sdk::{account::WritableAccount, pubkey::Pubkey, rent::Rent, stake},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_stake_program::stake_state,
|
|
|
|
solana_vote_program::vote_state::{self, VoteState, VoteStateVersions},
|
|
|
|
};
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-06-14 11:38:37 -07:00
|
|
|
// set up some dummies for a staked node (( vote ) ( stake ))
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn create_staked_node_accounts(
|
2021-03-09 13:06:07 -08:00
|
|
|
stake: u64,
|
|
|
|
) -> ((Pubkey, AccountSharedData), (Pubkey, AccountSharedData)) {
|
2020-10-19 12:12:08 -07:00
|
|
|
let vote_pubkey = solana_sdk::pubkey::new_rand();
|
2020-10-19 12:23:14 -07:00
|
|
|
let vote_account =
|
|
|
|
vote_state::create_account(&vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1);
|
2019-05-16 08:23:31 -07:00
|
|
|
(
|
2019-05-23 23:20:04 -07:00
|
|
|
(vote_pubkey, vote_account),
|
|
|
|
create_stake_account(stake, &vote_pubkey),
|
2019-05-16 08:23:31 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
// add stake to a vote_pubkey ( stake )
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn create_stake_account(
|
|
|
|
stake: u64,
|
|
|
|
vote_pubkey: &Pubkey,
|
|
|
|
) -> (Pubkey, AccountSharedData) {
|
2020-10-19 12:12:08 -07:00
|
|
|
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
2019-05-16 08:23:31 -07:00
|
|
|
(
|
2019-09-26 13:29:29 -07:00
|
|
|
stake_pubkey,
|
2019-08-15 18:58:46 -07:00
|
|
|
stake_state::create_account(
|
2019-09-26 13:29:29 -07:00
|
|
|
&stake_pubkey,
|
2021-06-18 06:34:46 -07:00
|
|
|
vote_pubkey,
|
|
|
|
&vote_state::create_account(vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1),
|
2019-11-12 12:33:40 -08:00
|
|
|
&Rent::free(),
|
2019-08-15 18:58:46 -07:00
|
|
|
stake,
|
|
|
|
),
|
2019-05-16 08:23:31 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
fn create_warming_staked_node_accounts(
|
2020-07-20 21:57:25 -07:00
|
|
|
stake: u64,
|
|
|
|
epoch: Epoch,
|
2021-03-09 13:06:07 -08:00
|
|
|
) -> ((Pubkey, AccountSharedData), (Pubkey, AccountSharedData)) {
|
2020-10-19 12:12:08 -07:00
|
|
|
let vote_pubkey = solana_sdk::pubkey::new_rand();
|
2020-10-19 12:23:14 -07:00
|
|
|
let vote_account =
|
|
|
|
vote_state::create_account(&vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1);
|
2020-07-20 21:57:25 -07:00
|
|
|
(
|
|
|
|
(vote_pubkey, vote_account),
|
|
|
|
create_warming_stake_account(stake, epoch, &vote_pubkey),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-12-13 17:26:34 -08:00
|
|
|
// add stake to a vote_pubkey ( stake )
|
2022-06-29 15:22:22 -07:00
|
|
|
fn create_warming_stake_account(
|
2020-07-20 21:57:25 -07:00
|
|
|
stake: u64,
|
|
|
|
epoch: Epoch,
|
|
|
|
vote_pubkey: &Pubkey,
|
2021-03-09 13:06:07 -08:00
|
|
|
) -> (Pubkey, AccountSharedData) {
|
2020-10-19 12:12:08 -07:00
|
|
|
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
2020-07-20 21:57:25 -07:00
|
|
|
(
|
|
|
|
stake_pubkey,
|
|
|
|
stake_state::create_account_with_activation_epoch(
|
|
|
|
&stake_pubkey,
|
2021-06-18 06:34:46 -07:00
|
|
|
vote_pubkey,
|
|
|
|
&vote_state::create_account(vote_pubkey, &solana_sdk::pubkey::new_rand(), 0, 1),
|
2020-07-20 21:57:25 -07:00
|
|
|
&Rent::free(),
|
|
|
|
stake,
|
|
|
|
epoch,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-05-16 08:23:31 -07:00
|
|
|
#[test]
|
|
|
|
fn test_stakes_basic() {
|
2019-08-12 20:59:57 -07:00
|
|
|
for i in 0..4 {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
2020-12-13 17:26:34 -08:00
|
|
|
epoch: i,
|
|
|
|
..Stakes::default()
|
2021-12-10 13:02:35 -08:00
|
|
|
});
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-06-19 11:54:52 -07:00
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, mut stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2021-06-15 09:04:00 -07:00
|
|
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
2019-06-19 11:54:52 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-06-19 11:54:52 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2019-08-12 20:59:57 -07:00
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-08-19 22:08:44 -07:00
|
|
|
stake.stake(i, None)
|
2019-08-12 20:59:57 -07:00
|
|
|
);
|
2019-06-19 11:54:52 -07:00
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-04-22 11:56:47 -07:00
|
|
|
stake_account.set_lamports(42);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-06-19 11:54:52 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-06-19 11:54:52 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2019-08-12 20:59:57 -07:00
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-08-19 22:08:44 -07:00
|
|
|
stake.stake(i, None)
|
2019-08-12 20:59:57 -07:00
|
|
|
); // stays old stake, because only 10 is activated
|
2019-06-19 11:54:52 -07:00
|
|
|
}
|
2019-06-10 16:17:29 -07:00
|
|
|
|
2019-06-19 11:54:52 -07:00
|
|
|
// activate more
|
|
|
|
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2021-06-15 09:04:00 -07:00
|
|
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
2019-06-19 11:54:52 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-06-19 11:54:52 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2019-08-12 20:59:57 -07:00
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-08-19 22:08:44 -07:00
|
|
|
stake.stake(i, None)
|
2019-08-12 20:59:57 -07:00
|
|
|
); // now stake of 42 is activated
|
2019-06-19 11:54:52 -07:00
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-04-22 11:56:47 -07:00
|
|
|
stake_account.set_lamports(0);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-06-19 11:54:52 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-06-19 11:54:52 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2019-06-19 11:54:52 -07:00
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 11:44:58 -07:00
|
|
|
#[test]
|
|
|
|
fn test_stakes_highest() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::default();
|
2019-06-11 11:44:58 -07:00
|
|
|
|
2021-12-10 13:02:35 -08:00
|
|
|
assert_eq!(stakes_cache.stakes().highest_staked_node(), None);
|
2019-06-11 11:44:58 -07:00
|
|
|
|
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-06-11 11:44:58 -07:00
|
|
|
|
|
|
|
let ((vote11_pubkey, vote11_account), (stake11_pubkey, stake11_account)) =
|
2019-06-19 11:54:52 -07:00
|
|
|
create_staked_node_accounts(20);
|
2019-06-11 11:44:58 -07:00
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote11_pubkey, &vote11_account);
|
|
|
|
stakes_cache.check_and_store(&stake11_pubkey, &stake11_account);
|
2019-06-11 11:44:58 -07:00
|
|
|
|
2022-08-03 23:12:59 -07:00
|
|
|
let vote11_node_pubkey = vote_state::from(&vote11_account).unwrap().node_pubkey;
|
2019-06-11 11:44:58 -07:00
|
|
|
|
2021-12-10 13:02:35 -08:00
|
|
|
let highest_staked_node = stakes_cache.stakes().highest_staked_node();
|
|
|
|
assert_eq!(highest_staked_node, Some(vote11_node_pubkey));
|
2019-06-11 11:44:58 -07:00
|
|
|
}
|
|
|
|
|
2019-05-16 08:23:31 -07:00
|
|
|
#[test]
|
|
|
|
fn test_stakes_vote_account_disappear_reappear() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
2020-12-13 17:26:34 -08:00
|
|
|
epoch: 4,
|
|
|
|
..Stakes::default()
|
2021-12-10 13:02:35 -08:00
|
|
|
});
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let ((vote_pubkey, mut vote_account), (stake_pubkey, stake_account)) =
|
2019-05-16 08:23:31 -07:00
|
|
|
create_staked_node_accounts(10);
|
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 10);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
|
2021-04-22 11:56:47 -07:00
|
|
|
vote_account.set_lamports(0);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_none());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
2021-02-24 09:00:48 -08:00
|
|
|
|
2021-04-22 11:56:47 -07:00
|
|
|
vote_account.set_lamports(1);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2021-02-24 09:00:48 -08:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2021-02-24 09:00:48 -08:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 10);
|
2021-02-24 09:00:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Vote account too big
|
2021-03-09 14:31:33 -08:00
|
|
|
let cache_data = vote_account.data().to_vec();
|
2021-03-25 09:04:20 -07:00
|
|
|
let mut pushed = vote_account.data().to_vec();
|
2021-03-23 13:19:31 -07:00
|
|
|
pushed.push(0);
|
|
|
|
vote_account.set_data(pushed);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2021-02-24 09:00:48 -08:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2021-02-24 09:00:48 -08:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_none());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2021-02-24 09:00:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Vote account uninitialized
|
|
|
|
let default_vote_state = VoteState::default();
|
|
|
|
let versioned = VoteStateVersions::new_current(default_vote_state);
|
2022-08-03 23:12:59 -07:00
|
|
|
vote_state::to(&versioned, &mut vote_account).unwrap();
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2021-02-24 09:00:48 -08:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2021-02-24 09:00:48 -08:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_none());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2021-02-24 09:00:48 -08:00
|
|
|
}
|
|
|
|
|
2021-03-11 14:40:45 -08:00
|
|
|
vote_account.set_data(cache_data);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 10);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_stakes_change_delegate() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
2020-12-13 17:26:34 -08:00
|
|
|
epoch: 4,
|
|
|
|
..Stakes::default()
|
2021-12-10 13:02:35 -08:00
|
|
|
});
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let ((vote_pubkey2, vote_account2), (_stake_pubkey2, stake_account2)) =
|
2019-05-16 08:23:31 -07:00
|
|
|
create_staked_node_accounts(10);
|
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&vote_pubkey2, &vote_account2);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
// delegates to vote_pubkey
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-06-15 09:04:00 -07:00
|
|
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
2019-06-19 11:54:52 -07:00
|
|
|
|
2019-05-16 08:23:31 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2019-06-19 11:54:52 -07:00
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-08-19 22:08:44 -07:00
|
|
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
2019-06-19 11:54:52 -07:00
|
|
|
);
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey2), 0);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
// delegates to vote_pubkey2
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account2);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
2019-06-19 11:54:52 -07:00
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey2),
|
2021-08-19 22:08:44 -07:00
|
|
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
2019-06-19 11:54:52 -07:00
|
|
|
);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_stakes_multiple_stakers() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
2020-12-13 17:26:34 -08:00
|
|
|
epoch: 4,
|
|
|
|
..Stakes::default()
|
2021-12-10 13:02:35 -08:00
|
|
|
});
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let (stake_pubkey2, stake_account2) = create_stake_account(10, &vote_pubkey);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
// delegates to vote_pubkey
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey2, &stake_account2);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 20);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
}
|
2021-10-05 21:53:26 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_activate_epoch() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::default();
|
2021-10-05 21:53:26 -07:00
|
|
|
|
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2021-10-05 21:53:26 -07:00
|
|
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2021-10-05 21:53:26 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-10-05 21:53:26 -07:00
|
|
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let thread_pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
2021-12-10 13:02:35 -08:00
|
|
|
stakes_cache.activate_epoch(3, &thread_pool);
|
2021-10-05 21:53:26 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2021-10-05 21:53:26 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
|
|
|
assert_eq!(
|
2022-06-25 13:03:15 -07:00
|
|
|
vote_accounts.get_delegated_stake(&vote_pubkey),
|
2021-10-05 21:53:26 -07:00
|
|
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-16 08:23:31 -07:00
|
|
|
#[test]
|
|
|
|
fn test_stakes_not_delegate() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
2020-12-13 17:26:34 -08:00
|
|
|
epoch: 4,
|
|
|
|
..Stakes::default()
|
2021-12-10 13:02:35 -08:00
|
|
|
});
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2019-05-23 23:20:04 -07:00
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_staked_node_accounts(10);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2019-05-16 08:23:31 -07:00
|
|
|
|
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 10);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// not a stake account, and whacks above entry
|
2021-12-10 13:02:35 -08:00
|
|
|
stakes_cache.check_and_store(
|
2019-11-20 10:12:43 -08:00
|
|
|
&stake_pubkey,
|
2021-06-15 09:04:00 -07:00
|
|
|
&AccountSharedData::new(1, 0, &stake::program::id()),
|
2019-11-20 10:12:43 -08:00
|
|
|
);
|
2019-05-16 08:23:31 -07:00
|
|
|
{
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2019-05-16 08:23:31 -07:00
|
|
|
let vote_accounts = stakes.vote_accounts();
|
2019-05-23 23:20:04 -07:00
|
|
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
2022-06-25 13:03:15 -07:00
|
|
|
assert_eq!(vote_accounts.get_delegated_stake(&vote_pubkey), 0);
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|
|
|
|
}
|
2020-07-20 21:57:25 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_balance_and_staked_empty() {
|
2022-04-08 06:45:26 -07:00
|
|
|
let stakes = Stakes::<StakeAccount>::default();
|
2020-07-20 21:57:25 -07:00
|
|
|
assert_eq!(stakes.vote_balance_and_staked(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_balance_and_staked_normal() {
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes_cache = StakesCache::default();
|
2022-04-08 06:45:26 -07:00
|
|
|
impl Stakes<StakeAccount> {
|
2022-06-29 15:22:22 -07:00
|
|
|
fn vote_balance_and_warmed_staked(&self) -> u64 {
|
2022-06-25 13:03:15 -07:00
|
|
|
let vote_balance: u64 = self
|
|
|
|
.vote_accounts
|
2020-07-20 21:57:25 -07:00
|
|
|
.iter()
|
2022-06-25 13:03:15 -07:00
|
|
|
.map(|(_pubkey, account)| account.lamports())
|
|
|
|
.sum();
|
|
|
|
let warmed_stake: u64 = self
|
|
|
|
.vote_accounts
|
2022-06-29 15:22:22 -07:00
|
|
|
.delegated_stakes()
|
2022-06-25 13:03:15 -07:00
|
|
|
.map(|(_pubkey, stake)| stake)
|
|
|
|
.sum();
|
|
|
|
vote_balance + warmed_stake
|
2020-07-20 21:57:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let genesis_epoch = 0;
|
|
|
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
|
|
|
create_warming_staked_node_accounts(10, genesis_epoch);
|
2021-12-14 06:23:36 -08:00
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
2020-07-20 21:57:25 -07:00
|
|
|
|
2021-12-10 13:02:35 -08:00
|
|
|
{
|
|
|
|
let stakes = stakes_cache.stakes();
|
|
|
|
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
|
|
|
assert_eq!(stakes.vote_balance_and_warmed_staked(), 1);
|
|
|
|
}
|
2020-07-20 21:57:25 -07:00
|
|
|
|
2021-10-05 21:53:26 -07:00
|
|
|
let thread_pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
2020-07-20 21:57:25 -07:00
|
|
|
for (epoch, expected_warmed_stake) in ((genesis_epoch + 1)..=3).zip(&[2, 3, 4]) {
|
2021-12-10 13:02:35 -08:00
|
|
|
stakes_cache.activate_epoch(epoch, &thread_pool);
|
2020-07-20 21:57:25 -07:00
|
|
|
// vote_balance_and_staked() always remain to return same lamports
|
|
|
|
// while vote_balance_and_warmed_staked() gradually increases
|
2021-12-10 13:02:35 -08:00
|
|
|
let stakes = stakes_cache.stakes();
|
2020-07-20 21:57:25 -07:00
|
|
|
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
|
|
|
assert_eq!(
|
|
|
|
stakes.vote_balance_and_warmed_staked(),
|
|
|
|
*expected_warmed_stake
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2022-04-11 14:07:52 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_serde_stakes_enum_compat() {
|
|
|
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
struct Dummy {
|
|
|
|
head: String,
|
|
|
|
#[serde(with = "serde_stakes_enum_compat")]
|
|
|
|
stakes: Arc<StakesEnum>,
|
|
|
|
tail: String,
|
|
|
|
}
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let stakes_cache = StakesCache::new(Stakes {
|
|
|
|
unused: rng.gen(),
|
|
|
|
epoch: rng.gen(),
|
|
|
|
..Stakes::default()
|
|
|
|
});
|
|
|
|
for _ in 0..rng.gen_range(5usize, 10) {
|
|
|
|
let vote_pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
let vote_account = vote_state::create_account(
|
|
|
|
&vote_pubkey,
|
|
|
|
&solana_sdk::pubkey::new_rand(), // node_pubkey
|
|
|
|
rng.gen_range(0, 101), // commission
|
|
|
|
rng.gen_range(0, 1_000_000), // lamports
|
|
|
|
);
|
|
|
|
stakes_cache.check_and_store(&vote_pubkey, &vote_account);
|
|
|
|
for _ in 0..rng.gen_range(10usize, 20) {
|
|
|
|
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
let rent = Rent::with_slots_per_epoch(rng.gen());
|
|
|
|
let stake_account = stake_state::create_account(
|
|
|
|
&stake_pubkey, // authorized
|
|
|
|
&vote_pubkey,
|
|
|
|
&vote_account,
|
|
|
|
&rent,
|
|
|
|
rng.gen_range(0, 1_000_000), // lamports
|
|
|
|
);
|
|
|
|
stakes_cache.check_and_store(&stake_pubkey, &stake_account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let stakes: Stakes<StakeAccount> = stakes_cache.stakes().clone();
|
|
|
|
assert!(stakes.vote_accounts.as_ref().len() >= 5);
|
|
|
|
assert!(stakes.stake_delegations.len() >= 50);
|
|
|
|
let dummy = Dummy {
|
|
|
|
head: String::from("dummy-head"),
|
|
|
|
stakes: Arc::new(StakesEnum::from(stakes.clone())),
|
|
|
|
tail: String::from("dummy-tail"),
|
|
|
|
};
|
|
|
|
assert!(dummy.stakes.vote_accounts().as_ref().len() >= 5);
|
|
|
|
let data = bincode::serialize(&dummy).unwrap();
|
|
|
|
let other: Dummy = bincode::deserialize(&data).unwrap();
|
|
|
|
assert_eq!(other, dummy);
|
2022-04-15 07:17:13 -07:00
|
|
|
let stakes = Stakes::<Delegation>::from(stakes);
|
2022-04-11 14:07:52 -07:00
|
|
|
assert!(stakes.vote_accounts.as_ref().len() >= 5);
|
|
|
|
assert!(stakes.stake_delegations.len() >= 50);
|
|
|
|
let other = match &*other.stakes {
|
|
|
|
StakesEnum::Accounts(_) => panic!("wrong type!"),
|
|
|
|
StakesEnum::Delegations(delegations) => delegations,
|
|
|
|
};
|
|
|
|
assert_eq!(other, &stakes)
|
|
|
|
}
|
2019-05-16 08:23:31 -07:00
|
|
|
}
|