2021-08-10 05:59:12 -07:00
|
|
|
use {
|
|
|
|
itertools::Itertools,
|
2022-06-29 04:45:53 -07:00
|
|
|
once_cell::sync::OnceCell,
|
2022-05-05 09:33:10 -07:00
|
|
|
serde::ser::{Serialize, Serializer},
|
2021-08-10 05:59:12 -07:00
|
|
|
solana_sdk::{
|
2022-06-24 13:08:01 -07:00
|
|
|
account::{accounts_equal, AccountSharedData, ReadableAccount},
|
2021-12-03 09:00:31 -08:00
|
|
|
instruction::InstructionError,
|
|
|
|
pubkey::Pubkey,
|
2021-08-10 05:59:12 -07:00
|
|
|
},
|
|
|
|
solana_vote_program::vote_state::VoteState,
|
|
|
|
std::{
|
|
|
|
cmp::Ordering,
|
|
|
|
collections::{hash_map::Entry, HashMap},
|
|
|
|
iter::FromIterator,
|
2022-06-29 15:22:22 -07:00
|
|
|
sync::Arc,
|
2021-08-10 05:59:12 -07:00
|
|
|
},
|
2022-05-06 09:22:49 -07:00
|
|
|
thiserror::Error,
|
2020-12-17 13:22:50 -08:00
|
|
|
};
|
2020-11-30 09:18:33 -08:00
|
|
|
|
2022-05-06 09:22:49 -07:00
|
|
|
#[derive(Clone, Debug, PartialEq, AbiExample, Deserialize)]
|
2022-06-24 13:08:01 -07:00
|
|
|
#[serde(try_from = "AccountSharedData")]
|
2021-08-10 07:39:50 -07:00
|
|
|
pub struct VoteAccount(Arc<VoteAccountInner>);
|
2020-11-30 09:18:33 -08:00
|
|
|
|
2022-05-06 09:22:49 -07:00
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum Error {
|
|
|
|
#[error(transparent)]
|
|
|
|
InstructionError(#[from] InstructionError),
|
|
|
|
#[error("Invalid vote account owner: {0}")]
|
|
|
|
InvalidOwner(/*owner:*/ Pubkey),
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:18:33 -08:00
|
|
|
#[derive(Debug, AbiExample)]
|
2021-08-10 07:39:50 -07:00
|
|
|
struct VoteAccountInner {
|
2022-06-24 13:08:01 -07:00
|
|
|
account: AccountSharedData,
|
2022-06-29 04:45:53 -07:00
|
|
|
vote_state: OnceCell<Result<VoteState, Error>>,
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
|
2021-10-05 21:53:26 -07:00
|
|
|
pub type VoteAccountsHashMap = HashMap<Pubkey, (/*stake:*/ u64, VoteAccount)>;
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
#[derive(Clone, Debug, AbiExample, Deserialize)]
|
2022-05-05 09:33:10 -07:00
|
|
|
#[serde(from = "Arc<VoteAccountsHashMap>")]
|
2020-12-17 13:22:50 -08:00
|
|
|
pub struct VoteAccounts {
|
2021-10-05 21:53:26 -07:00
|
|
|
vote_accounts: Arc<VoteAccountsHashMap>,
|
2022-06-29 15:22:22 -07:00
|
|
|
// Inner Arc is meant to implement copy-on-write semantics.
|
|
|
|
staked_nodes: OnceCell<
|
2021-08-10 05:59:12 -07:00
|
|
|
Arc<
|
|
|
|
HashMap<
|
|
|
|
Pubkey, // VoteAccount.vote_state.node_pubkey.
|
|
|
|
u64, // Total stake across all vote-accounts.
|
|
|
|
>,
|
2020-12-17 13:22:50 -08:00
|
|
|
>,
|
|
|
|
>,
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
impl VoteAccount {
|
2021-08-30 08:54:01 -07:00
|
|
|
pub(crate) fn lamports(&self) -> u64 {
|
2022-04-04 06:20:26 -07:00
|
|
|
self.0.account.lamports()
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:55 -07:00
|
|
|
pub(crate) fn owner(&self) -> &Pubkey {
|
|
|
|
self.0.account.owner()
|
|
|
|
}
|
|
|
|
|
2022-06-29 04:45:53 -07:00
|
|
|
pub fn vote_state(&self) -> &Result<VoteState, Error> {
|
|
|
|
// VoteState::deserialize deserializes a VoteStateVersions and then
|
|
|
|
// calls VoteStateVersions::convert_to_current.
|
|
|
|
self.0
|
|
|
|
.vote_state
|
|
|
|
.get_or_init(|| VoteState::deserialize(self.0.account.data()).map_err(Error::from))
|
2021-12-10 13:02:35 -08:00
|
|
|
}
|
|
|
|
|
2022-04-04 06:20:26 -07:00
|
|
|
pub(crate) fn is_deserialized(&self) -> bool {
|
2022-06-29 04:45:53 -07:00
|
|
|
self.0.vote_state.get().is_some()
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
2020-12-17 13:22:50 -08:00
|
|
|
|
|
|
|
/// VoteState.node_pubkey of this vote-account.
|
2022-06-27 07:09:06 -07:00
|
|
|
pub fn node_pubkey(&self) -> Option<Pubkey> {
|
2020-12-17 13:22:50 -08:00
|
|
|
Some(self.vote_state().as_ref().ok()?.node_pubkey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VoteAccounts {
|
2022-04-20 07:07:28 -07:00
|
|
|
pub(crate) fn len(&self) -> usize {
|
|
|
|
self.vote_accounts.len()
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub fn staked_nodes(&self) -> Arc<HashMap</*node_pubkey:*/ Pubkey, /*stake:*/ u64>> {
|
|
|
|
self.staked_nodes
|
|
|
|
.get_or_init(|| {
|
|
|
|
Arc::new(
|
|
|
|
self.vote_accounts
|
|
|
|
.values()
|
|
|
|
.filter(|(stake, _)| *stake != 0u64)
|
|
|
|
.filter_map(|(stake, vote_account)| {
|
|
|
|
Some((vote_account.node_pubkey()?, stake))
|
|
|
|
})
|
|
|
|
.into_grouping_map()
|
|
|
|
.aggregate(|acc, _node_pubkey, stake| {
|
|
|
|
Some(acc.unwrap_or_default() + stake)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get(&self, pubkey: &Pubkey) -> Option<&VoteAccount> {
|
|
|
|
let (_stake, vote_account) = self.vote_accounts.get(pubkey)?;
|
|
|
|
Some(vote_account)
|
2021-08-30 08:54:01 -07:00
|
|
|
}
|
|
|
|
|
2022-06-25 09:41:35 -07:00
|
|
|
pub fn get_delegated_stake(&self, pubkey: &Pubkey) -> u64 {
|
|
|
|
self.vote_accounts
|
|
|
|
.get(pubkey)
|
2022-06-29 15:22:22 -07:00
|
|
|
.map(|(stake, _vote_account)| *stake)
|
2022-06-25 09:41:35 -07:00
|
|
|
.unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
2022-06-25 13:03:15 -07:00
|
|
|
pub(crate) fn iter(&self) -> impl Iterator<Item = (&Pubkey, &VoteAccount)> {
|
|
|
|
self.vote_accounts
|
|
|
|
.iter()
|
|
|
|
.map(|(vote_pubkey, (_stake, vote_account))| (vote_pubkey, vote_account))
|
|
|
|
}
|
|
|
|
|
2022-06-29 15:22:22 -07:00
|
|
|
pub(crate) fn delegated_stakes(&self) -> impl Iterator<Item = (&Pubkey, u64)> {
|
2022-06-25 13:03:15 -07:00
|
|
|
self.vote_accounts
|
|
|
|
.iter()
|
2022-06-29 15:22:22 -07:00
|
|
|
.map(|(vote_pubkey, (stake, _vote_account))| (vote_pubkey, *stake))
|
2022-06-25 13:03:15 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn find_max_by_delegated_stake(&self) -> Option<&VoteAccount> {
|
|
|
|
let key = |(_pubkey, (stake, _vote_account)): &(_, &(u64, _))| *stake;
|
|
|
|
let (_pubkey, (_stake, vote_account)) = self.vote_accounts.iter().max_by_key(key)?;
|
|
|
|
Some(vote_account)
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
pub(crate) fn insert(&mut self, pubkey: Pubkey, (stake, vote_account): (u64, VoteAccount)) {
|
2020-12-17 13:22:50 -08:00
|
|
|
self.add_node_stake(stake, &vote_account);
|
2021-08-30 08:54:01 -07:00
|
|
|
let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
|
|
|
|
if let Some((stake, vote_account)) = vote_accounts.insert(pubkey, (stake, vote_account)) {
|
2020-12-17 13:22:50 -08:00
|
|
|
self.sub_node_stake(stake, &vote_account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
pub(crate) fn remove(&mut self, pubkey: &Pubkey) -> Option<(u64, VoteAccount)> {
|
|
|
|
let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
|
|
|
|
let entry = vote_accounts.remove(pubkey);
|
|
|
|
if let Some((stake, ref vote_account)) = entry {
|
2020-12-17 13:22:50 -08:00
|
|
|
self.sub_node_stake(stake, vote_account);
|
|
|
|
}
|
2021-08-30 08:54:01 -07:00
|
|
|
entry
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
pub(crate) fn add_stake(&mut self, pubkey: &Pubkey, delta: u64) {
|
|
|
|
let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
|
|
|
|
if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
|
2020-12-17 13:22:50 -08:00
|
|
|
*stake += delta;
|
|
|
|
let vote_account = vote_account.clone();
|
|
|
|
self.add_node_stake(delta, &vote_account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
pub(crate) fn sub_stake(&mut self, pubkey: &Pubkey, delta: u64) {
|
|
|
|
let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
|
|
|
|
if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
|
2020-12-17 13:22:50 -08:00
|
|
|
*stake = stake
|
|
|
|
.checked_sub(delta)
|
|
|
|
.expect("subtraction value exceeds account's stake");
|
|
|
|
let vote_account = vote_account.clone();
|
|
|
|
self.sub_node_stake(delta, &vote_account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
fn add_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
|
2022-06-29 15:22:22 -07:00
|
|
|
if stake == 0u64 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let staked_nodes = match self.staked_nodes.get_mut() {
|
|
|
|
None => return,
|
|
|
|
Some(staked_nodes) => staked_nodes,
|
|
|
|
};
|
|
|
|
if let Some(node_pubkey) = vote_account.node_pubkey() {
|
|
|
|
Arc::make_mut(staked_nodes)
|
|
|
|
.entry(node_pubkey)
|
|
|
|
.and_modify(|s| *s += stake)
|
|
|
|
.or_insert(stake);
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
fn sub_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
|
2022-06-29 15:22:22 -07:00
|
|
|
if stake == 0u64 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let staked_nodes = match self.staked_nodes.get_mut() {
|
|
|
|
None => return,
|
|
|
|
Some(staked_nodes) => staked_nodes,
|
|
|
|
};
|
|
|
|
if let Some(node_pubkey) = vote_account.node_pubkey() {
|
|
|
|
match Arc::make_mut(staked_nodes).entry(node_pubkey) {
|
|
|
|
Entry::Vacant(_) => panic!("this should not happen!"),
|
|
|
|
Entry::Occupied(mut entry) => match entry.get().cmp(&stake) {
|
|
|
|
Ordering::Less => panic!("subtraction value exceeds node's stake"),
|
|
|
|
Ordering::Equal => {
|
|
|
|
entry.remove_entry();
|
|
|
|
}
|
|
|
|
Ordering::Greater => *entry.get_mut() -= stake,
|
|
|
|
},
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
impl Serialize for VoteAccount {
|
2020-11-30 09:18:33 -08:00
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2021-08-05 13:44:07 -07:00
|
|
|
self.0.account.serialize(serializer)
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
impl From<VoteAccount> for AccountSharedData {
|
|
|
|
fn from(account: VoteAccount) -> Self {
|
2022-06-24 13:08:01 -07:00
|
|
|
account.0.account.clone()
|
2022-04-08 06:45:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-24 13:08:01 -07:00
|
|
|
impl TryFrom<AccountSharedData> for VoteAccount {
|
2022-05-06 09:22:49 -07:00
|
|
|
type Error = Error;
|
2022-06-24 13:08:01 -07:00
|
|
|
fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccountInner::try_from(account)?;
|
|
|
|
Ok(Self(Arc::new(vote_account)))
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-24 13:08:01 -07:00
|
|
|
impl TryFrom<AccountSharedData> for VoteAccountInner {
|
2022-05-06 09:22:49 -07:00
|
|
|
type Error = Error;
|
2022-06-24 13:08:01 -07:00
|
|
|
fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
|
2022-05-06 09:22:49 -07:00
|
|
|
if !solana_vote_program::check_id(account.owner()) {
|
|
|
|
return Err(Error::InvalidOwner(*account.owner()));
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
2022-05-06 09:22:49 -07:00
|
|
|
Ok(Self {
|
|
|
|
account,
|
2022-06-29 04:45:53 -07:00
|
|
|
vote_state: OnceCell::new(),
|
2022-05-06 09:22:49 -07:00
|
|
|
})
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
impl PartialEq<VoteAccountInner> for VoteAccountInner {
|
2020-11-30 09:18:33 -08:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2022-04-24 07:33:42 -07:00
|
|
|
let Self {
|
|
|
|
account,
|
|
|
|
vote_state: _,
|
|
|
|
} = self;
|
|
|
|
account == &other.account
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-20 07:07:28 -07:00
|
|
|
impl PartialEq<AccountSharedData> for VoteAccount {
|
|
|
|
fn eq(&self, other: &AccountSharedData) -> bool {
|
2022-04-23 06:28:21 -07:00
|
|
|
accounts_equal(&self.0.account, other)
|
2022-04-20 07:07:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-17 13:22:50 -08:00
|
|
|
impl Default for VoteAccounts {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-08-30 08:54:01 -07:00
|
|
|
vote_accounts: Arc::default(),
|
2022-06-29 15:22:22 -07:00
|
|
|
staked_nodes: OnceCell::new(),
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq<VoteAccounts> for VoteAccounts {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2022-04-24 07:33:42 -07:00
|
|
|
let Self {
|
|
|
|
vote_accounts,
|
|
|
|
staked_nodes: _,
|
|
|
|
} = self;
|
|
|
|
vote_accounts == &other.vote_accounts
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
impl From<Arc<VoteAccountsHashMap>> for VoteAccounts {
|
|
|
|
fn from(vote_accounts: Arc<VoteAccountsHashMap>) -> Self {
|
2020-12-17 13:22:50 -08:00
|
|
|
Self {
|
|
|
|
vote_accounts,
|
2022-06-29 15:22:22 -07:00
|
|
|
staked_nodes: OnceCell::new(),
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-16 11:21:33 -07:00
|
|
|
impl AsRef<VoteAccountsHashMap> for VoteAccounts {
|
|
|
|
fn as_ref(&self) -> &VoteAccountsHashMap {
|
2020-12-17 13:22:50 -08:00
|
|
|
&self.vote_accounts
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-30 08:54:01 -07:00
|
|
|
impl From<&VoteAccounts> for Arc<VoteAccountsHashMap> {
|
|
|
|
fn from(vote_accounts: &VoteAccounts) -> Self {
|
|
|
|
Arc::clone(&vote_accounts.vote_accounts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-10 07:39:50 -07:00
|
|
|
impl FromIterator<(Pubkey, (/*stake:*/ u64, VoteAccount))> for VoteAccounts {
|
2020-12-17 13:22:50 -08:00
|
|
|
fn from_iter<I>(iter: I) -> Self
|
|
|
|
where
|
2021-08-10 07:39:50 -07:00
|
|
|
I: IntoIterator<Item = (Pubkey, (u64, VoteAccount))>,
|
2020-12-17 13:22:50 -08:00
|
|
|
{
|
2021-08-30 08:54:01 -07:00
|
|
|
Self::from(Arc::new(HashMap::from_iter(iter)))
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for VoteAccounts {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
self.vote_accounts.serialize(serializer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:18:33 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
bincode::Options,
|
|
|
|
rand::Rng,
|
|
|
|
solana_sdk::{pubkey::Pubkey, sysvar::clock::Clock},
|
|
|
|
solana_vote_program::vote_state::{VoteInit, VoteStateVersions},
|
|
|
|
std::iter::repeat_with,
|
|
|
|
};
|
2020-11-30 09:18:33 -08:00
|
|
|
|
2020-12-17 13:22:50 -08:00
|
|
|
fn new_rand_vote_account<R: Rng>(
|
|
|
|
rng: &mut R,
|
|
|
|
node_pubkey: Option<Pubkey>,
|
2022-06-24 13:08:01 -07:00
|
|
|
) -> (AccountSharedData, VoteState) {
|
2020-11-30 09:18:33 -08:00
|
|
|
let vote_init = VoteInit {
|
2020-12-17 13:22:50 -08:00
|
|
|
node_pubkey: node_pubkey.unwrap_or_else(Pubkey::new_unique),
|
2020-11-30 09:18:33 -08:00
|
|
|
authorized_voter: Pubkey::new_unique(),
|
|
|
|
authorized_withdrawer: Pubkey::new_unique(),
|
|
|
|
commission: rng.gen(),
|
|
|
|
};
|
|
|
|
let clock = Clock {
|
|
|
|
slot: rng.gen(),
|
|
|
|
epoch_start_timestamp: rng.gen(),
|
|
|
|
epoch: rng.gen(),
|
|
|
|
leader_schedule_epoch: rng.gen(),
|
|
|
|
unix_timestamp: rng.gen(),
|
|
|
|
};
|
|
|
|
let vote_state = VoteState::new(&vote_init, &clock);
|
2022-06-24 13:08:01 -07:00
|
|
|
let account = AccountSharedData::new_data(
|
2020-11-30 09:18:33 -08:00
|
|
|
rng.gen(), // lamports
|
2020-12-21 15:19:04 -08:00
|
|
|
&VoteStateVersions::new_current(vote_state.clone()),
|
2022-05-06 09:22:49 -07:00
|
|
|
&solana_vote_program::id(), // owner
|
2020-11-30 09:18:33 -08:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
(account, vote_state)
|
|
|
|
}
|
|
|
|
|
2020-12-17 13:22:50 -08:00
|
|
|
fn new_rand_vote_accounts<R: Rng>(
|
|
|
|
rng: &mut R,
|
|
|
|
num_nodes: usize,
|
2021-08-10 07:39:50 -07:00
|
|
|
) -> impl Iterator<Item = (Pubkey, (/*stake:*/ u64, VoteAccount))> + '_ {
|
2020-12-17 13:22:50 -08:00
|
|
|
let nodes: Vec<_> = repeat_with(Pubkey::new_unique).take(num_nodes).collect();
|
|
|
|
repeat_with(move || {
|
|
|
|
let node = nodes[rng.gen_range(0, nodes.len())];
|
|
|
|
let (account, _) = new_rand_vote_account(rng, Some(node));
|
|
|
|
let stake = rng.gen_range(0, 997);
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccount::try_from(account).unwrap();
|
|
|
|
(Pubkey::new_unique(), (stake, vote_account))
|
2020-12-17 13:22:50 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn staked_nodes<'a, I>(vote_accounts: I) -> HashMap<Pubkey, u64>
|
|
|
|
where
|
2021-08-10 07:39:50 -07:00
|
|
|
I: IntoIterator<Item = &'a (Pubkey, (u64, VoteAccount))>,
|
2020-12-17 13:22:50 -08:00
|
|
|
{
|
|
|
|
let mut staked_nodes = HashMap::new();
|
|
|
|
for (_, (stake, vote_account)) in vote_accounts
|
|
|
|
.into_iter()
|
|
|
|
.filter(|(_, (stake, _))| *stake != 0)
|
|
|
|
{
|
|
|
|
if let Some(node_pubkey) = vote_account.node_pubkey() {
|
|
|
|
staked_nodes
|
|
|
|
.entry(node_pubkey)
|
|
|
|
.and_modify(|s| *s += *stake)
|
|
|
|
.or_insert(*stake);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
staked_nodes
|
|
|
|
}
|
|
|
|
|
2020-11-30 09:18:33 -08:00
|
|
|
#[test]
|
|
|
|
fn test_vote_account() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2020-12-17 13:22:50 -08:00
|
|
|
let (account, vote_state) = new_rand_vote_account(&mut rng, None);
|
2022-03-16 07:50:12 -07:00
|
|
|
let lamports = account.lamports();
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccount::try_from(account).unwrap();
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(lamports, vote_account.lamports());
|
|
|
|
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
|
|
|
|
// 2nd call to .vote_state() should return the cached value.
|
|
|
|
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_account_serialize() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2020-12-17 13:22:50 -08:00
|
|
|
let (account, vote_state) = new_rand_vote_account(&mut rng, None);
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccount::try_from(account.clone()).unwrap();
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
|
2021-08-10 07:39:50 -07:00
|
|
|
// Assert than VoteAccount has the same wire format as Account.
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(
|
|
|
|
bincode::serialize(&account).unwrap(),
|
|
|
|
bincode::serialize(&vote_account).unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_account_deserialize() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2020-12-17 13:22:50 -08:00
|
|
|
let (account, vote_state) = new_rand_vote_account(&mut rng, None);
|
2020-11-30 09:18:33 -08:00
|
|
|
let data = bincode::serialize(&account).unwrap();
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccount::try_from(account).unwrap();
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
|
2021-08-10 07:39:50 -07:00
|
|
|
let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(vote_account, other_vote_account);
|
|
|
|
assert_eq!(
|
|
|
|
vote_state,
|
|
|
|
*other_vote_account.vote_state().as_ref().unwrap()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_account_round_trip() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2020-12-17 13:22:50 -08:00
|
|
|
let (account, vote_state) = new_rand_vote_account(&mut rng, None);
|
2022-05-06 09:22:49 -07:00
|
|
|
let vote_account = VoteAccount::try_from(account).unwrap();
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
|
|
|
|
let data = bincode::serialize(&vote_account).unwrap();
|
2021-08-10 07:39:50 -07:00
|
|
|
let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
|
|
|
|
// Assert that serialize->deserialized returns the same VoteAccount.
|
2020-11-30 09:18:33 -08:00
|
|
|
assert_eq!(vote_account, other_vote_account);
|
|
|
|
assert_eq!(
|
|
|
|
vote_state,
|
|
|
|
*other_vote_account.vote_state().as_ref().unwrap()
|
|
|
|
);
|
|
|
|
}
|
2020-12-17 13:22:50 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_accounts_serialize() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2022-03-24 10:09:48 -07:00
|
|
|
let vote_accounts_hash_map: VoteAccountsHashMap =
|
2020-12-17 13:22:50 -08:00
|
|
|
new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
|
2021-08-30 08:54:01 -07:00
|
|
|
let vote_accounts = VoteAccounts::from(Arc::new(vote_accounts_hash_map.clone()));
|
2020-12-17 13:22:50 -08:00
|
|
|
assert!(vote_accounts.staked_nodes().len() > 32);
|
|
|
|
assert_eq!(
|
|
|
|
bincode::serialize(&vote_accounts).unwrap(),
|
|
|
|
bincode::serialize(&vote_accounts_hash_map).unwrap(),
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
bincode::options().serialize(&vote_accounts).unwrap(),
|
|
|
|
bincode::options()
|
|
|
|
.serialize(&vote_accounts_hash_map)
|
|
|
|
.unwrap(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_vote_accounts_deserialize() {
|
|
|
|
let mut rng = rand::thread_rng();
|
2022-03-24 10:09:48 -07:00
|
|
|
let vote_accounts_hash_map: VoteAccountsHashMap =
|
2020-12-17 13:22:50 -08:00
|
|
|
new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
|
|
|
|
let data = bincode::serialize(&vote_accounts_hash_map).unwrap();
|
|
|
|
let vote_accounts: VoteAccounts = bincode::deserialize(&data).unwrap();
|
|
|
|
assert!(vote_accounts.staked_nodes().len() > 32);
|
2021-08-30 08:54:01 -07:00
|
|
|
assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
|
2020-12-17 13:22:50 -08:00
|
|
|
let data = bincode::options()
|
|
|
|
.serialize(&vote_accounts_hash_map)
|
|
|
|
.unwrap();
|
|
|
|
let vote_accounts: VoteAccounts = bincode::options().deserialize(&data).unwrap();
|
2021-08-30 08:54:01 -07:00
|
|
|
assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_staked_nodes() {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let mut accounts: Vec<_> = new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
|
|
|
|
let mut vote_accounts = VoteAccounts::default();
|
|
|
|
// Add vote accounts.
|
|
|
|
for (k, (pubkey, (stake, vote_account))) in accounts.iter().enumerate() {
|
|
|
|
vote_accounts.insert(*pubkey, (*stake, vote_account.clone()));
|
|
|
|
if (k + 1) % 128 == 0 {
|
|
|
|
assert_eq!(
|
|
|
|
staked_nodes(&accounts[..k + 1]),
|
2021-08-10 05:59:12 -07:00
|
|
|
*vote_accounts.staked_nodes()
|
2020-12-17 13:22:50 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove some of the vote accounts.
|
|
|
|
for k in 0..256 {
|
|
|
|
let index = rng.gen_range(0, accounts.len());
|
|
|
|
let (pubkey, (_, _)) = accounts.swap_remove(index);
|
|
|
|
vote_accounts.remove(&pubkey);
|
|
|
|
if (k + 1) % 32 == 0 {
|
2021-08-10 05:59:12 -07:00
|
|
|
assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Modify the stakes for some of the accounts.
|
|
|
|
for k in 0..2048 {
|
|
|
|
let index = rng.gen_range(0, accounts.len());
|
|
|
|
let (pubkey, (stake, _)) = &mut accounts[index];
|
|
|
|
let new_stake = rng.gen_range(0, 997);
|
|
|
|
if new_stake < *stake {
|
|
|
|
vote_accounts.sub_stake(pubkey, *stake - new_stake);
|
|
|
|
} else {
|
|
|
|
vote_accounts.add_stake(pubkey, new_stake - *stake);
|
|
|
|
}
|
|
|
|
*stake = new_stake;
|
|
|
|
if (k + 1) % 128 == 0 {
|
2021-08-10 05:59:12 -07:00
|
|
|
assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove everything.
|
|
|
|
while !accounts.is_empty() {
|
|
|
|
let index = rng.gen_range(0, accounts.len());
|
|
|
|
let (pubkey, (_, _)) = accounts.swap_remove(index);
|
|
|
|
vote_accounts.remove(&pubkey);
|
|
|
|
if accounts.len() % 32 == 0 {
|
2021-08-10 05:59:12 -07:00
|
|
|
assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
|
|
|
}
|
2022-06-29 15:22:22 -07:00
|
|
|
assert!(vote_accounts.staked_nodes.get().unwrap().is_empty());
|
2020-12-17 13:22:50 -08:00
|
|
|
}
|
2021-08-10 05:59:12 -07:00
|
|
|
|
|
|
|
// Asserts that returned staked-nodes are copy-on-write references.
|
|
|
|
#[test]
|
|
|
|
fn test_staked_nodes_cow() {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let mut accounts = new_rand_vote_accounts(&mut rng, 64);
|
|
|
|
// Add vote accounts.
|
|
|
|
let mut vote_accounts = VoteAccounts::default();
|
|
|
|
for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
|
|
|
|
vote_accounts.insert(pubkey, (stake, vote_account));
|
|
|
|
}
|
|
|
|
let staked_nodes = vote_accounts.staked_nodes();
|
|
|
|
let (pubkey, (more_stake, vote_account)) =
|
|
|
|
accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
|
|
|
|
let node_pubkey = vote_account.node_pubkey().unwrap();
|
|
|
|
vote_accounts.insert(pubkey, (more_stake, vote_account));
|
|
|
|
assert_ne!(staked_nodes, vote_accounts.staked_nodes());
|
|
|
|
assert_eq!(
|
|
|
|
vote_accounts.staked_nodes()[&node_pubkey],
|
|
|
|
more_stake + staked_nodes.get(&node_pubkey).copied().unwrap_or_default()
|
|
|
|
);
|
|
|
|
for (pubkey, stake) in vote_accounts.staked_nodes().iter() {
|
|
|
|
if *pubkey != node_pubkey {
|
|
|
|
assert_eq!(*stake, staked_nodes[pubkey]);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
*stake,
|
|
|
|
more_stake + staked_nodes.get(pubkey).copied().unwrap_or_default()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-30 08:54:01 -07:00
|
|
|
|
|
|
|
// Asserts that returned vote-accounts are copy-on-write references.
|
|
|
|
#[test]
|
|
|
|
fn test_vote_accounts_cow() {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let mut accounts = new_rand_vote_accounts(&mut rng, 64);
|
|
|
|
// Add vote accounts.
|
|
|
|
let mut vote_accounts = VoteAccounts::default();
|
|
|
|
for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
|
|
|
|
vote_accounts.insert(pubkey, (stake, vote_account));
|
|
|
|
}
|
|
|
|
let vote_accounts_hashmap = Arc::<VoteAccountsHashMap>::from(&vote_accounts);
|
|
|
|
assert_eq!(vote_accounts_hashmap, vote_accounts.vote_accounts);
|
|
|
|
assert!(Arc::ptr_eq(
|
|
|
|
&vote_accounts_hashmap,
|
|
|
|
&vote_accounts.vote_accounts
|
|
|
|
));
|
|
|
|
let (pubkey, (more_stake, vote_account)) =
|
|
|
|
accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
|
|
|
|
vote_accounts.insert(pubkey, (more_stake, vote_account.clone()));
|
|
|
|
assert!(!Arc::ptr_eq(
|
|
|
|
&vote_accounts_hashmap,
|
|
|
|
&vote_accounts.vote_accounts
|
|
|
|
));
|
|
|
|
assert_ne!(vote_accounts_hashmap, vote_accounts.vote_accounts);
|
|
|
|
let other = (more_stake, vote_account);
|
2022-06-25 13:03:15 -07:00
|
|
|
for (pk, value) in vote_accounts.vote_accounts.iter() {
|
2021-08-30 08:54:01 -07:00
|
|
|
if *pk != pubkey {
|
|
|
|
assert_eq!(value, &vote_accounts_hashmap[pk]);
|
|
|
|
} else {
|
|
|
|
assert_eq!(value, &other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-30 09:18:33 -08:00
|
|
|
}
|