solana_runtime/
stake_account.rs1#[cfg(feature = "dev-context-only-utils")]
2use qualifier_attr::qualifiers;
3use {
4 solana_account::{AccountSharedData, ReadableAccount, state_traits::StateMut},
5 solana_instruction::error::InstructionError,
6 solana_pubkey::Pubkey,
7 solana_stake_interface::{
8 program as stake_program,
9 state::{Delegation, Stake, StakeStateV2},
10 },
11 std::marker::PhantomData,
12 thiserror::Error,
13 wincode::SchemaWrite,
14};
15#[cfg(feature = "frozen-abi")]
16use {
17 solana_frozen_abi::{abi_example::AbiExample, stable_abi::StableAbi},
18 solana_stake_interface::{stake_flags::StakeFlags, state::Meta},
19};
20
21#[cfg_attr(feature = "frozen-abi", derive(StableAbi, StableAbiSample))]
26#[derive(Clone, Debug, Default)]
27pub struct StakeAccount<T> {
28 #[cfg_attr(feature = "frozen-abi", stable_abi_sample(with = "Default::default()"))]
30 account: AccountSharedData,
31 #[cfg_attr(
32 feature = "frozen-abi",
33 stable_abi_sample(with = "sample_delegated_stake_state(rng)")
34 )]
35 stake_state: StakeStateV2,
36 _phantom: PhantomData<T>,
37}
38
39unsafe impl<C: wincode::config::Config> SchemaWrite<C> for StakeAccount<Delegation> {
44 type Src = Self;
45
46 const TYPE_META: wincode::TypeMeta =
47 <Delegation as SchemaWrite<C>>::TYPE_META.keep_zero_copy(false);
48
49 fn size_of(src: &Self::Src) -> wincode::WriteResult<usize> {
50 <Delegation as SchemaWrite<C>>::size_of(src.delegation())
51 }
52
53 fn write(writer: impl wincode::io::Writer, src: &Self::Src) -> wincode::WriteResult<()> {
54 <Delegation as SchemaWrite<C>>::write(writer, src.delegation())
55 }
56}
57
58#[cfg(feature = "frozen-abi")]
61fn sample_delegated_stake_state(
62 rng: &mut (impl solana_frozen_abi::rand::RngCore + ?Sized),
63) -> StakeStateV2 {
64 StakeStateV2::Stake(
65 Meta::random(rng),
66 Stake::random(rng),
67 StakeFlags::random(rng),
68 )
69}
70
71#[derive(Debug, Error)]
72pub enum Error {
73 #[error(transparent)]
74 InstructionError(#[from] InstructionError),
75 #[error("Invalid delegation: {0:?}")]
76 InvalidDelegation(Box<StakeStateV2>),
77 #[error("Invalid stake account owner: {0}")]
78 InvalidOwner(Pubkey),
79}
80
81impl<T> StakeAccount<T> {
82 #[inline]
83 pub(crate) fn lamports(&self) -> u64 {
84 self.account.lamports()
85 }
86
87 #[inline]
88 pub(crate) fn stake_state(&self) -> &StakeStateV2 {
89 &self.stake_state
90 }
91
92 #[inline]
93 pub(crate) fn data_len(&self) -> usize {
94 self.account.data().len()
95 }
96}
97
98impl StakeAccount<Delegation> {
99 #[inline]
100 #[cfg_attr(feature = "dev-context-only-utils", qualifiers(pub))]
101 pub(crate) fn delegation(&self) -> &Delegation {
102 self.stake_state.delegation_ref().unwrap()
105 }
106
107 #[inline]
108 pub(crate) fn stake(&self) -> &Stake {
109 self.stake_state.stake_ref().unwrap()
112 }
113}
114
115impl TryFrom<AccountSharedData> for StakeAccount<Delegation> {
116 type Error = Error;
117 fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
118 if account.owner() != &stake_program::id() {
119 return Err(Error::InvalidOwner(*account.owner()));
120 }
121 let stake_state: StakeStateV2 = account.state()?;
122 if stake_state.delegation().is_none() {
123 return Err(Error::InvalidDelegation(Box::new(stake_state)));
124 }
125 Ok(Self {
126 account,
127 stake_state,
128 _phantom: PhantomData,
129 })
130 }
131}
132
133impl<T> From<StakeAccount<T>> for (AccountSharedData, StakeStateV2) {
134 #[inline]
135 fn from(stake_account: StakeAccount<T>) -> Self {
136 (stake_account.account, stake_account.stake_state)
137 }
138}
139
140impl<S, T> PartialEq<StakeAccount<S>> for StakeAccount<T> {
141 fn eq(&self, other: &StakeAccount<S>) -> bool {
142 let StakeAccount {
143 account,
144 stake_state,
145 _phantom,
146 } = other;
147 account == &self.account && stake_state == &self.stake_state
148 }
149}
150
151#[cfg(feature = "frozen-abi")]
152impl AbiExample for StakeAccount<Delegation> {
153 fn example() -> Self {
154 use solana_account::Account;
155 let stake_state =
156 StakeStateV2::Stake(Meta::example(), Stake::example(), StakeFlags::example());
157 let mut account = Account::example();
158 account.data.resize(200, 0u8);
159 account.owner = stake_program::id();
160 account.set_state(&stake_state).unwrap();
161 Self::try_from(AccountSharedData::from(account)).unwrap()
162 }
163}