solana/runtime/src/vote_account.rs

182 lines
5.8 KiB
Rust
Raw Normal View History

use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use solana_sdk::{account::Account, instruction::InstructionError};
use solana_vote_program::vote_state::VoteState;
use std::ops::Deref;
use std::sync::{Arc, Once, RwLock, RwLockReadGuard};
// The value here does not matter. It will be overwritten
// at the first call to VoteAccount::vote_state().
const INVALID_VOTE_STATE: Result<VoteState, InstructionError> =
Err(InstructionError::InvalidAccountData);
#[derive(Clone, Debug, Default, PartialEq, AbiExample)]
pub struct ArcVoteAccount(Arc<VoteAccount>);
#[derive(Debug, AbiExample)]
pub struct VoteAccount {
account: Account,
vote_state: RwLock<Result<VoteState, InstructionError>>,
vote_state_once: Once,
}
impl VoteAccount {
pub fn lamports(&self) -> u64 {
self.account.lamports
}
pub fn vote_state(&self) -> RwLockReadGuard<Result<VoteState, InstructionError>> {
self.vote_state_once.call_once(|| {
*self.vote_state.write().unwrap() = VoteState::deserialize(&self.account.data);
});
self.vote_state.read().unwrap()
}
}
impl Deref for ArcVoteAccount {
type Target = VoteAccount;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl Serialize for ArcVoteAccount {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.account.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for ArcVoteAccount {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let account = Account::deserialize(deserializer)?;
Ok(Self::from(account))
}
}
impl From<Account> for ArcVoteAccount {
fn from(account: Account) -> Self {
Self(Arc::new(VoteAccount::from(account)))
}
}
impl From<Account> for VoteAccount {
fn from(account: Account) -> Self {
Self {
account,
vote_state: RwLock::new(INVALID_VOTE_STATE),
vote_state_once: Once::new(),
}
}
}
impl Default for VoteAccount {
fn default() -> Self {
Self {
account: Account::default(),
vote_state: RwLock::new(INVALID_VOTE_STATE),
vote_state_once: Once::new(),
}
}
}
impl PartialEq<VoteAccount> for VoteAccount {
fn eq(&self, other: &Self) -> bool {
self.account == other.account
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
use solana_sdk::{pubkey::Pubkey, sysvar::clock::Clock};
use solana_vote_program::vote_state::{VoteInit, VoteStateVersions};
fn new_rand_vote_account<R: Rng>(rng: &mut R) -> (Account, VoteState) {
let vote_init = VoteInit {
node_pubkey: Pubkey::new_unique(),
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);
let account = Account::new_data(
rng.gen(), // lamports
&VoteStateVersions::Current(Box::new(vote_state.clone())),
&Pubkey::new_unique(), // owner
)
.unwrap();
(account, vote_state)
}
#[test]
fn test_vote_account() {
let mut rng = rand::thread_rng();
let (account, vote_state) = new_rand_vote_account(&mut rng);
let lamports = account.lamports;
let vote_account = ArcVoteAccount::from(account);
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();
let (account, vote_state) = new_rand_vote_account(&mut rng);
let vote_account = ArcVoteAccount::from(account.clone());
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
// Assert than ArcVoteAccount has the same wire format as Account.
assert_eq!(
bincode::serialize(&account).unwrap(),
bincode::serialize(&vote_account).unwrap()
);
}
#[test]
fn test_vote_account_deserialize() {
let mut rng = rand::thread_rng();
let (account, vote_state) = new_rand_vote_account(&mut rng);
let data = bincode::serialize(&account).unwrap();
let vote_account = ArcVoteAccount::from(account);
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
let other_vote_account: ArcVoteAccount = bincode::deserialize(&data).unwrap();
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();
let (account, vote_state) = new_rand_vote_account(&mut rng);
let vote_account = ArcVoteAccount::from(account);
assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
let data = bincode::serialize(&vote_account).unwrap();
let other_vote_account: ArcVoteAccount = bincode::deserialize(&data).unwrap();
// Assert that serialize->deserialized returns the same ArcVoteAccount.
assert_eq!(vote_account, other_vote_account);
assert_eq!(
vote_state,
*other_vote_account.vote_state().as_ref().unwrap()
);
}
}