2022-04-08 06:45:26 -07:00
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
|
|
|
use solana_frozen_abi::abi_example::AbiExample;
|
2022-04-08 06:26:24 -07:00
|
|
|
use {
|
|
|
|
solana_sdk::{
|
|
|
|
account::{AccountSharedData, ReadableAccount},
|
|
|
|
account_utils::StateMut,
|
|
|
|
instruction::InstructionError,
|
|
|
|
pubkey::Pubkey,
|
2023-08-10 16:07:21 -07:00
|
|
|
stake::state::{Delegation, StakeStateV2},
|
2022-04-08 06:26:24 -07:00
|
|
|
},
|
2022-04-15 07:17:13 -07:00
|
|
|
std::marker::PhantomData,
|
2022-04-08 06:26:24 -07:00
|
|
|
thiserror::Error,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// An account and a stake state deserialized from the account.
|
2022-04-23 06:28:21 -07:00
|
|
|
/// Generic type T enforces type-safety so that StakeAccount<Delegation> can
|
2022-04-15 07:17:13 -07:00
|
|
|
/// only wrap a stake-state which is a Delegation; whereas StakeAccount<()>
|
|
|
|
/// wraps any account with stake state.
|
2022-04-20 07:07:28 -07:00
|
|
|
#[derive(Clone, Debug, Default)]
|
2022-04-15 07:17:13 -07:00
|
|
|
pub struct StakeAccount<T> {
|
|
|
|
account: AccountSharedData,
|
2023-08-10 16:07:21 -07:00
|
|
|
stake_state: StakeStateV2,
|
2022-04-15 07:17:13 -07:00
|
|
|
_phantom: PhantomData<T>,
|
|
|
|
}
|
2022-04-08 06:26:24 -07:00
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
2022-04-15 07:17:13 -07:00
|
|
|
#[allow(clippy::enum_variant_names)]
|
2022-04-11 14:07:52 -07:00
|
|
|
pub enum Error {
|
2022-04-08 06:26:24 -07:00
|
|
|
#[error(transparent)]
|
|
|
|
InstructionError(#[from] InstructionError),
|
2022-04-15 07:17:13 -07:00
|
|
|
#[error("Invalid delegation: {0:?}")]
|
2023-08-10 16:07:21 -07:00
|
|
|
InvalidDelegation(Box<StakeStateV2>),
|
2022-05-06 09:22:49 -07:00
|
|
|
#[error("Invalid stake account owner: {0}")]
|
|
|
|
InvalidOwner(/*owner:*/ Pubkey),
|
2022-04-08 06:26:24 -07:00
|
|
|
}
|
|
|
|
|
2022-04-15 07:17:13 -07:00
|
|
|
impl<T> StakeAccount<T> {
|
2022-04-08 06:45:26 -07:00
|
|
|
#[inline]
|
|
|
|
pub(crate) fn lamports(&self) -> u64 {
|
2022-04-15 07:17:13 -07:00
|
|
|
self.account.lamports()
|
2022-04-08 06:45:26 -07:00
|
|
|
}
|
|
|
|
|
2022-04-08 06:26:24 -07:00
|
|
|
#[inline]
|
2023-08-10 16:07:21 -07:00
|
|
|
pub(crate) fn stake_state(&self) -> &StakeStateV2 {
|
2022-04-15 07:17:13 -07:00
|
|
|
&self.stake_state
|
2022-04-08 06:26:24 -07:00
|
|
|
}
|
2022-04-15 07:17:13 -07:00
|
|
|
}
|
2022-04-08 06:45:26 -07:00
|
|
|
|
2022-04-15 07:17:13 -07:00
|
|
|
impl StakeAccount<Delegation> {
|
2022-04-08 06:45:26 -07:00
|
|
|
#[inline]
|
2022-04-15 07:17:13 -07:00
|
|
|
pub(crate) fn delegation(&self) -> Delegation {
|
2022-09-28 07:46:25 -07:00
|
|
|
// Safe to unwrap here because StakeAccount<Delegation> will always
|
2022-04-15 07:17:13 -07:00
|
|
|
// only wrap a stake-state which is a delegation.
|
|
|
|
self.stake_state.delegation().unwrap()
|
2022-04-08 06:45:26 -07:00
|
|
|
}
|
2022-04-08 06:26:24 -07:00
|
|
|
}
|
|
|
|
|
2023-07-29 13:47:28 -07:00
|
|
|
impl TryFrom<AccountSharedData> for StakeAccount<Delegation> {
|
2022-04-08 06:26:24 -07:00
|
|
|
type Error = Error;
|
|
|
|
fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
|
|
|
|
if account.owner() != &solana_stake_program::id() {
|
2022-05-06 09:22:49 -07:00
|
|
|
return Err(Error::InvalidOwner(*account.owner()));
|
2022-04-08 06:26:24 -07:00
|
|
|
}
|
2023-08-10 16:07:21 -07:00
|
|
|
let stake_state: StakeStateV2 = account.state()?;
|
2023-07-29 13:47:28 -07:00
|
|
|
if stake_state.delegation().is_none() {
|
|
|
|
return Err(Error::InvalidDelegation(Box::new(stake_state)));
|
|
|
|
}
|
2022-04-15 07:17:13 -07:00
|
|
|
Ok(Self {
|
|
|
|
account,
|
|
|
|
stake_state,
|
2023-02-23 14:59:08 -08:00
|
|
|
_phantom: PhantomData,
|
2022-04-15 07:17:13 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-10 16:07:21 -07:00
|
|
|
impl<T> From<StakeAccount<T>> for (AccountSharedData, StakeStateV2) {
|
2022-04-15 07:17:13 -07:00
|
|
|
#[inline]
|
|
|
|
fn from(stake_account: StakeAccount<T>) -> Self {
|
|
|
|
(stake_account.account, stake_account.stake_state)
|
2022-04-08 06:26:24 -07:00
|
|
|
}
|
|
|
|
}
|
2022-04-08 06:45:26 -07:00
|
|
|
|
2022-04-20 07:07:28 -07:00
|
|
|
impl<S, T> PartialEq<StakeAccount<S>> for StakeAccount<T> {
|
|
|
|
fn eq(&self, other: &StakeAccount<S>) -> bool {
|
|
|
|
let StakeAccount {
|
|
|
|
account,
|
|
|
|
stake_state,
|
|
|
|
_phantom,
|
|
|
|
} = other;
|
|
|
|
account == &self.account && stake_state == &self.stake_state
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:45:26 -07:00
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
2022-04-15 07:17:13 -07:00
|
|
|
impl AbiExample for StakeAccount<Delegation> {
|
2022-04-08 06:45:26 -07:00
|
|
|
fn example() -> Self {
|
|
|
|
use solana_sdk::{
|
|
|
|
account::Account,
|
2023-07-24 07:09:40 -07:00
|
|
|
stake::{
|
|
|
|
stake_flags::StakeFlags,
|
|
|
|
state::{Meta, Stake},
|
|
|
|
},
|
2022-04-08 06:45:26 -07:00
|
|
|
};
|
2023-07-24 07:09:40 -07:00
|
|
|
let stake_state =
|
2023-08-10 16:07:21 -07:00
|
|
|
StakeStateV2::Stake(Meta::example(), Stake::example(), StakeFlags::example());
|
2022-04-08 06:45:26 -07:00
|
|
|
let mut account = Account::example();
|
2023-07-24 07:09:40 -07:00
|
|
|
account.data.resize(200, 0u8);
|
2022-04-08 06:45:26 -07:00
|
|
|
account.owner = solana_stake_program::id();
|
2022-05-22 09:17:59 -07:00
|
|
|
account.set_state(&stake_state).unwrap();
|
2022-04-08 06:45:26 -07:00
|
|
|
Self::try_from(AccountSharedData::from(account)).unwrap()
|
|
|
|
}
|
|
|
|
}
|