Add stake_flags to stake state (#32524)

add stake_flags to stake state

Co-authored-by: HaoranYi <haoran.yi@solana.com>
This commit is contained in:
HaoranYi 2023-07-24 09:09:40 -05:00 committed by GitHub
parent 8e5805797e
commit 17af3ab10a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 153 additions and 109 deletions

View File

@ -19,7 +19,7 @@ pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
meta: meta.into(), meta: meta.into(),
stake: None, stake: None,
}), }),
StakeState::Stake(meta, stake) => StakeAccountType::Delegated(UiStakeAccount { StakeState::Stake(meta, stake, _) => StakeAccountType::Delegated(UiStakeAccount {
meta: meta.into(), meta: meta.into(),
stake: Some(stake.into()), stake: Some(stake.into()),
}), }),
@ -136,7 +136,7 @@ impl From<Delegation> for UiDelegation {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use {super::*, bincode::serialize}; use {super::*, bincode::serialize, solana_sdk::stake::stake_flags::StakeFlags};
#[test] #[test]
fn test_parse_stake() { fn test_parse_stake() {
@ -194,7 +194,7 @@ mod test {
credits_observed: 10, credits_observed: 10,
}; };
let stake_state = StakeState::Stake(meta, stake); let stake_state = StakeState::Stake(meta, stake, StakeFlags::empty());
let stake_data = serialize(&stake_state).unwrap(); let stake_data = serialize(&stake_state).unwrap();
assert_eq!( assert_eq!(
parse_stake(&stake_data).unwrap(), parse_stake(&stake_data).unwrap(),

View File

@ -1819,7 +1819,7 @@ pub fn process_show_stakes(
}); });
} }
} }
StakeState::Stake(_, stake) => { StakeState::Stake(_, stake, _) => {
if vote_account_pubkeys.is_none() if vote_account_pubkeys.is_none()
|| vote_account_pubkeys || vote_account_pubkeys
.unwrap() .unwrap()

View File

@ -1628,7 +1628,7 @@ pub fn process_deactivate_stake_account(
let vote_account_address = match stake_account.state() { let vote_account_address = match stake_account.state() {
Ok(stake_state) => match stake_state { Ok(stake_state) => match stake_state {
StakeState::Stake(_, stake) => stake.delegation.voter_pubkey, StakeState::Stake(_, stake, _) => stake.delegation.voter_pubkey,
_ => { _ => {
return Err(CliError::BadParameter(format!( return Err(CliError::BadParameter(format!(
"{stake_account_address} is not a delegated stake account", "{stake_account_address} is not a delegated stake account",
@ -2195,6 +2195,7 @@ pub fn build_stake_state(
lockup, lockup,
}, },
stake, stake,
_,
) => { ) => {
let current_epoch = clock.epoch; let current_epoch = clock.epoch;
let StakeActivationStatus { let StakeActivationStatus {

View File

@ -165,7 +165,7 @@ fn test_stake_redelegation() {
let stake_state: StakeState = stake_account.state().unwrap(); let stake_state: StakeState = stake_account.state().unwrap();
let rent_exempt_reserve = match stake_state { let rent_exempt_reserve = match stake_state {
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, _) => {
assert_eq!(stake.delegation.voter_pubkey, vote_keypair.pubkey()); assert_eq!(stake.delegation.voter_pubkey, vote_keypair.pubkey());
meta.rent_exempt_reserve meta.rent_exempt_reserve
} }
@ -271,7 +271,7 @@ fn test_stake_redelegation() {
let stake2_state: StakeState = stake2_account.state().unwrap(); let stake2_state: StakeState = stake2_account.state().unwrap();
match stake2_state { match stake2_state {
StakeState::Stake(_meta, stake) => { StakeState::Stake(_meta, stake, _) => {
assert_eq!(stake.delegation.voter_pubkey, vote2_keypair.pubkey()); assert_eq!(stake.delegation.voter_pubkey, vote2_keypair.pubkey());
} }
_ => panic!("Unexpected stake2 state!"), _ => panic!("Unexpected stake2 state!"),

View File

@ -2965,7 +2965,7 @@ fn main() {
.unwrap() .unwrap()
.into_iter() .into_iter()
{ {
if let Ok(StakeState::Stake(meta, stake)) = account.state() { if let Ok(StakeState::Stake(meta, stake, _)) = account.state() {
if vote_accounts_to_destake if vote_accounts_to_destake
.contains(&stake.delegation.voter_pubkey) .contains(&stake.delegation.voter_pubkey)
{ {

View File

@ -481,6 +481,7 @@ mod tests {
set_lockup_checked, AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs, set_lockup_checked, AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs,
LockupArgs, StakeError, LockupArgs, StakeError,
}, },
stake_flags::StakeFlags,
state::{Authorized, Lockup, StakeActivationStatus, StakeAuthorize}, state::{Authorized, Lockup, StakeActivationStatus, StakeAuthorize},
MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION,
}, },
@ -610,6 +611,7 @@ mod tests {
}, },
..Stake::default() ..Stake::default()
}, },
StakeFlags::empty(),
) )
} }
@ -2721,7 +2723,7 @@ mod tests {
StakeState::Initialized(_meta) => { StakeState::Initialized(_meta) => {
assert_eq!(from(&accounts[0]).unwrap(), state); assert_eq!(from(&accounts[0]).unwrap(), state);
} }
StakeState::Stake(_meta, _stake) => { StakeState::Stake(_meta, _stake, _) => {
let stake_0 = from(&accounts[0]).unwrap().stake(); let stake_0 = from(&accounts[0]).unwrap().stake();
assert_eq!(stake_0.unwrap().delegation.stake, stake_lamports / 2); assert_eq!(stake_0.unwrap().delegation.stake, stake_lamports / 2);
} }
@ -4316,8 +4318,8 @@ mod tests {
// *must* equal the split amount. Otherwise, the split amount must first be used to // *must* equal the split amount. Otherwise, the split amount must first be used to
// make the destination rent exempt, and then the leftover lamports are delegated. // make the destination rent exempt, and then the leftover lamports are delegated.
if expected_result.is_ok() { if expected_result.is_ok() {
assert_matches!(accounts[0].state().unwrap(), StakeState::Stake(_, _)); assert_matches!(accounts[0].state().unwrap(), StakeState::Stake(_, _, _));
if let StakeState::Stake(_, destination_stake) = accounts[1].state().unwrap() { if let StakeState::Stake(_, destination_stake, _) = accounts[1].state().unwrap() {
let destination_initial_rent_deficit = let destination_initial_rent_deficit =
rent_exempt_reserve.saturating_sub(destination_starting_balance); rent_exempt_reserve.saturating_sub(destination_starting_balance);
let expected_destination_stake_delegation = let expected_destination_stake_delegation =
@ -4737,7 +4739,7 @@ mod tests {
for split_to_state in &[ for split_to_state in &[
StakeState::Initialized(Meta::default()), StakeState::Initialized(Meta::default()),
StakeState::Stake(Meta::default(), Stake::default()), StakeState::Stake(Meta::default(), Stake::default(), StakeFlags::default()),
StakeState::RewardsPool, StakeState::RewardsPool,
] { ] {
let split_to_account = AccountSharedData::new_data_with_space( let split_to_account = AccountSharedData::new_data_with_space(
@ -4903,7 +4905,7 @@ mod tests {
); );
// verify no stake leakage in the case of a stake // verify no stake leakage in the case of a stake
if let StakeState::Stake(meta, stake) = state { if let StakeState::Stake(meta, stake, stake_flags) = state {
assert_eq!( assert_eq!(
accounts[1].state(), accounts[1].state(),
Ok(StakeState::Stake( Ok(StakeState::Stake(
@ -4914,7 +4916,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..*stake ..*stake
} },
*stake_flags,
)) ))
); );
assert_eq!(accounts[0].lamports(), *minimum_balance,); assert_eq!(accounts[0].lamports(), *minimum_balance,);
@ -5005,7 +5008,7 @@ mod tests {
stake_lamports + initial_balance, stake_lamports + initial_balance,
); );
if let StakeState::Stake(meta, stake) = state { if let StakeState::Stake(meta, stake, stake_flags) = state {
let expected_stake = let expected_stake =
stake_lamports / 2 - (rent_exempt_reserve.saturating_sub(initial_balance)); stake_lamports / 2 - (rent_exempt_reserve.saturating_sub(initial_balance));
assert_eq!( assert_eq!(
@ -5018,7 +5021,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..stake ..stake
} },
stake_flags
)), )),
accounts[1].state(), accounts[1].state(),
); );
@ -5037,7 +5041,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..stake ..stake
} },
stake_flags,
)), )),
accounts[0].state(), accounts[0].state(),
); );
@ -5128,7 +5133,7 @@ mod tests {
stake_lamports + initial_balance stake_lamports + initial_balance
); );
if let StakeState::Stake(meta, stake) = state { if let StakeState::Stake(meta, stake, stake_flags) = state {
let expected_split_meta = Meta { let expected_split_meta = Meta {
authorized: Authorized::auto(&stake_address), authorized: Authorized::auto(&stake_address),
rent_exempt_reserve: split_rent_exempt_reserve, rent_exempt_reserve: split_rent_exempt_reserve,
@ -5146,7 +5151,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..stake ..stake
} },
stake_flags,
)), )),
accounts[1].state() accounts[1].state()
); );
@ -5165,7 +5171,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..stake ..stake
} },
stake_flags,
)), )),
accounts[0].state() accounts[0].state()
); );
@ -5321,7 +5328,7 @@ mod tests {
assert_eq!(Ok(*state), accounts[1].state()); assert_eq!(Ok(*state), accounts[1].state());
assert_eq!(Ok(StakeState::Uninitialized), accounts[0].state()); assert_eq!(Ok(StakeState::Uninitialized), accounts[0].state());
} }
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, stake_flags) => {
assert_eq!( assert_eq!(
Ok(StakeState::Stake( Ok(StakeState::Stake(
*meta, *meta,
@ -5331,7 +5338,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..*stake ..*stake
} },
*stake_flags
)), )),
accounts[1].state() accounts[1].state()
); );
@ -5416,7 +5424,7 @@ mod tests {
stake_lamports + initial_balance stake_lamports + initial_balance
); );
if let StakeState::Stake(meta, stake) = state { if let StakeState::Stake(meta, stake, stake_flags) = state {
assert_eq!( assert_eq!(
Ok(StakeState::Stake( Ok(StakeState::Stake(
meta, meta,
@ -5426,7 +5434,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..stake ..stake
} },
stake_flags,
)), )),
accounts[1].state() accounts[1].state()
); );
@ -5538,7 +5547,7 @@ mod tests {
); );
assert_eq!(Ok(StakeState::Uninitialized), accounts[0].state()); assert_eq!(Ok(StakeState::Uninitialized), accounts[0].state());
} }
StakeState::Stake(_meta, stake) => { StakeState::Stake(_meta, stake, stake_flags) => {
// Expected stake should reflect original stake amount so that extra lamports // Expected stake should reflect original stake amount so that extra lamports
// from the rent_exempt_reserve inequality do not magically activate // from the rent_exempt_reserve inequality do not magically activate
let expected_stake = stake_lamports - source_rent_exempt_reserve; let expected_stake = stake_lamports - source_rent_exempt_reserve;
@ -5552,7 +5561,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..*stake ..*stake
} },
*stake_flags,
)), )),
accounts[1].state() accounts[1].state()
); );
@ -5667,7 +5677,7 @@ mod tests {
StakeState::Initialized(meta) => { StakeState::Initialized(meta) => {
assert_eq!(accounts[0].state(), Ok(StakeState::Initialized(*meta)),); assert_eq!(accounts[0].state(), Ok(StakeState::Initialized(*meta)),);
} }
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, stake_flags) => {
let expected_stake = stake.delegation.stake let expected_stake = stake.delegation.stake
+ merge_from_state + merge_from_state
.stake() .stake()
@ -5686,7 +5696,8 @@ mod tests {
..stake.delegation ..stake.delegation
}, },
..*stake ..*stake
} },
*stake_flags,
)), )),
); );
} }
@ -5720,7 +5731,7 @@ mod tests {
}; };
let stake_account = AccountSharedData::new_data_with_space( let stake_account = AccountSharedData::new_data_with_space(
stake_lamports, stake_lamports,
&StakeState::Stake(meta, stake), &StakeState::Stake(meta, stake, StakeFlags::empty()),
StakeState::size_of(), StakeState::size_of(),
&id(), &id(),
) )
@ -6047,7 +6058,7 @@ mod tests {
}; };
let stake_account = AccountSharedData::new_data_with_space( let stake_account = AccountSharedData::new_data_with_space(
stake_lamports, stake_lamports,
&StakeState::Stake(meta, stake), &StakeState::Stake(meta, stake, StakeFlags::empty()),
StakeState::size_of(), StakeState::size_of(),
&id(), &id(),
) )
@ -6063,7 +6074,7 @@ mod tests {
}; };
let merge_from_account = AccountSharedData::new_data_with_space( let merge_from_account = AccountSharedData::new_data_with_space(
merge_from_lamports, merge_from_lamports,
&StakeState::Stake(meta, merge_from_stake), &StakeState::Stake(meta, merge_from_stake, StakeFlags::empty()),
StakeState::size_of(), StakeState::size_of(),
&id(), &id(),
) )
@ -6219,7 +6230,7 @@ mod tests {
}; };
transaction_accounts[0] transaction_accounts[0]
.1 .1
.set_state(&StakeState::Stake(meta, stake)) .set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
.unwrap(); .unwrap();
} }
if clock.epoch == merge_from_deactivation_epoch { if clock.epoch == merge_from_deactivation_epoch {
@ -6233,7 +6244,11 @@ mod tests {
}; };
transaction_accounts[1] transaction_accounts[1]
.1 .1
.set_state(&StakeState::Stake(meta, merge_from_stake)) .set_state(&StakeState::Stake(
meta,
merge_from_stake,
StakeFlags::empty(),
))
.unwrap(); .unwrap();
} }
stake_history.add( stake_history.add(
@ -6394,6 +6409,7 @@ mod tests {
1, /* activation_epoch */ 1, /* activation_epoch */
&stake_config::Config::default(), &stake_config::Config::default(),
), ),
StakeFlags::empty(),
); );
let stake_account = AccountSharedData::new_data_with_space( let stake_account = AccountSharedData::new_data_with_space(
@ -6593,6 +6609,7 @@ mod tests {
1, /* activation_epoch */ 1, /* activation_epoch */
&stake_config::Config::default(), &stake_config::Config::default(),
), ),
StakeFlags::empty(),
)) ))
.unwrap(); .unwrap();
@ -6686,6 +6703,7 @@ mod tests {
activation_epoch, activation_epoch,
&stake_config::Config::default(), &stake_config::Config::default(),
), ),
StakeFlags::empty(),
); );
if let Some(expected_stake_activation_status) = expected_stake_activation_status { if let Some(expected_stake_activation_status) = expected_stake_activation_status {
@ -6816,7 +6834,7 @@ mod tests {
); );
assert_eq!(output_accounts[0].lamports(), rent_exempt_reserve); assert_eq!(output_accounts[0].lamports(), rent_exempt_reserve);
if let StakeState::Stake(meta, stake) = output_accounts[0].deserialize_data().unwrap() { if let StakeState::Stake(meta, stake, _) = output_accounts[0].deserialize_data().unwrap() {
assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve); assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve);
assert_eq!( assert_eq!(
stake.delegation.stake, stake.delegation.stake,
@ -6831,7 +6849,7 @@ mod tests {
output_accounts[1].lamports(), output_accounts[1].lamports(),
minimum_delegation + rent_exempt_reserve minimum_delegation + rent_exempt_reserve
); );
if let StakeState::Stake(meta, stake) = output_accounts[1].deserialize_data().unwrap() { if let StakeState::Stake(meta, stake, _) = output_accounts[1].deserialize_data().unwrap() {
assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve); assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve);
assert_eq!(stake.delegation.stake, minimum_delegation); assert_eq!(stake.delegation.stake, minimum_delegation);
assert_eq!(stake.delegation.activation_epoch, current_epoch); assert_eq!(stake.delegation.activation_epoch, current_epoch);
@ -6974,7 +6992,7 @@ mod tests {
output_accounts[1].lamports(), output_accounts[1].lamports(),
minimum_delegation + rent_exempt_reserve + 42 minimum_delegation + rent_exempt_reserve + 42
); );
if let StakeState::Stake(meta, stake) = output_accounts[1].deserialize_data().unwrap() { if let StakeState::Stake(meta, stake, _) = output_accounts[1].deserialize_data().unwrap() {
assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve); assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve);
assert_eq!(stake.delegation.stake, minimum_delegation + 42); assert_eq!(stake.delegation.stake, minimum_delegation + 42);
assert_eq!(stake.delegation.activation_epoch, current_epoch); assert_eq!(stake.delegation.activation_epoch, current_epoch);
@ -6988,12 +7006,12 @@ mod tests {
// //
let mut stake_account_over_allocated = let mut stake_account_over_allocated =
prepare_stake_account(0 /*activation_epoch:*/, None); prepare_stake_account(0 /*activation_epoch:*/, None);
if let StakeState::Stake(mut meta, stake) = if let StakeState::Stake(mut meta, stake, stake_flags) =
stake_account_over_allocated.deserialize_data().unwrap() stake_account_over_allocated.deserialize_data().unwrap()
{ {
meta.rent_exempt_reserve += 42; meta.rent_exempt_reserve += 42;
stake_account_over_allocated stake_account_over_allocated
.set_state(&StakeState::Stake(meta, stake)) .set_state(&StakeState::Stake(meta, stake, stake_flags))
.unwrap(); .unwrap();
} }
stake_account_over_allocated stake_account_over_allocated
@ -7016,7 +7034,7 @@ mod tests {
); );
assert_eq!(output_accounts[0].lamports(), rent_exempt_reserve + 42); assert_eq!(output_accounts[0].lamports(), rent_exempt_reserve + 42);
if let StakeState::Stake(meta, _stake) = output_accounts[0].deserialize_data().unwrap() { if let StakeState::Stake(meta, _stake, _) = output_accounts[0].deserialize_data().unwrap() {
assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve + 42); assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve + 42);
} else { } else {
panic!("Invalid output_accounts[0] data"); panic!("Invalid output_accounts[0] data");
@ -7025,7 +7043,7 @@ mod tests {
output_accounts[1].lamports(), output_accounts[1].lamports(),
minimum_delegation + rent_exempt_reserve, minimum_delegation + rent_exempt_reserve,
); );
if let StakeState::Stake(meta, stake) = output_accounts[1].deserialize_data().unwrap() { if let StakeState::Stake(meta, stake, _) = output_accounts[1].deserialize_data().unwrap() {
assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve); assert_eq!(meta.rent_exempt_reserve, rent_exempt_reserve);
assert_eq!(stake.delegation.stake, minimum_delegation); assert_eq!(stake.delegation.stake, minimum_delegation);
} else { } else {
@ -7163,7 +7181,7 @@ mod tests {
let mut deactivating_stake_account = let mut deactivating_stake_account =
prepare_stake_account(0 /*activation_epoch:*/, None); prepare_stake_account(0 /*activation_epoch:*/, None);
if let StakeState::Stake(meta, mut stake) = if let StakeState::Stake(meta, mut stake, _stake_flags) =
deactivating_stake_account.deserialize_data().unwrap() deactivating_stake_account.deserialize_data().unwrap()
{ {
stake.deactivate(current_epoch).unwrap(); stake.deactivate(current_epoch).unwrap();
@ -7179,7 +7197,7 @@ mod tests {
); );
deactivating_stake_account deactivating_stake_account
.set_state(&StakeState::Stake(meta, stake)) .set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
.unwrap(); .unwrap();
} }
let _ = process_instruction_redelegate( let _ = process_instruction_redelegate(
@ -7198,7 +7216,7 @@ mod tests {
// (less than `minimum_delegation + rent_exempt_reserve`) // (less than `minimum_delegation + rent_exempt_reserve`)
// //
let mut stake_account_too_few_lamports = stake_account.clone(); let mut stake_account_too_few_lamports = stake_account.clone();
if let StakeState::Stake(meta, mut stake) = if let StakeState::Stake(meta, mut stake, stake_flags) =
stake_account_too_few_lamports.deserialize_data().unwrap() stake_account_too_few_lamports.deserialize_data().unwrap()
{ {
stake.delegation.stake -= 1; stake.delegation.stake -= 1;
@ -7207,7 +7225,7 @@ mod tests {
minimum_delegation + rent_exempt_reserve - 1 minimum_delegation + rent_exempt_reserve - 1
); );
stake_account_too_few_lamports stake_account_too_few_lamports
.set_state(&StakeState::Stake(meta, stake)) .set_state(&StakeState::Stake(meta, stake, stake_flags))
.unwrap(); .unwrap();
} else { } else {
panic!("Invalid stake_account"); panic!("Invalid stake_account");
@ -7232,7 +7250,7 @@ mod tests {
); );
// //
// Failure: redelegate to same vote addresss // Failure: redelegate to same vote address
// //
let _ = process_instruction_redelegate( let _ = process_instruction_redelegate(
&stake_address, &stake_address,

View File

@ -25,6 +25,7 @@ use {
config::Config, config::Config,
instruction::{LockupArgs, StakeError}, instruction::{LockupArgs, StakeError},
program::id, program::id,
stake_flags::StakeFlags,
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent}, tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
}, },
stake_history::{StakeHistory, StakeHistoryEntry}, stake_history::{StakeHistory, StakeHistoryEntry},
@ -487,7 +488,7 @@ pub fn authorize(
custodian: Option<&Pubkey>, custodian: Option<&Pubkey>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
match stake_account.get_state()? { match stake_account.get_state()? {
StakeState::Stake(mut meta, stake) => { StakeState::Stake(mut meta, stake, stake_flags) => {
meta.authorized.authorize( meta.authorized.authorize(
signers, signers,
new_authority, new_authority,
@ -498,7 +499,7 @@ pub fn authorize(
None None
}, },
)?; )?;
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
} }
StakeState::Initialized(mut meta) => { StakeState::Initialized(mut meta) => {
meta.authorized.authorize( meta.authorized.authorize(
@ -590,9 +591,9 @@ pub fn delegate(
clock.epoch, clock.epoch,
config, config,
); );
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
} }
StakeState::Stake(meta, mut stake) => { StakeState::Stake(meta, mut stake, stake_flags) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?; meta.authorized.check(signers, StakeAuthorize::Staker)?;
let ValidatedDelegatedInfo { stake_amount } = let ValidatedDelegatedInfo { stake_amount } =
validate_delegated_amount(&stake_account, &meta, feature_set)?; validate_delegated_amount(&stake_account, &meta, feature_set)?;
@ -606,7 +607,7 @@ pub fn delegate(
stake_history, stake_history,
config, config,
)?; )?;
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
} }
_ => Err(InstructionError::InvalidAccountData), _ => Err(InstructionError::InvalidAccountData),
} }
@ -617,11 +618,11 @@ pub fn deactivate(
clock: &Clock, clock: &Clock,
signers: &HashSet<Pubkey>, signers: &HashSet<Pubkey>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if let StakeState::Stake(meta, mut stake) = stake_account.get_state()? { if let StakeState::Stake(meta, mut stake, stake_flags) = stake_account.get_state()? {
meta.authorized.check(signers, StakeAuthorize::Staker)?; meta.authorized.check(signers, StakeAuthorize::Staker)?;
stake.deactivate(clock.epoch)?; stake.deactivate(clock.epoch)?;
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
} else { } else {
Err(InstructionError::InvalidAccountData) Err(InstructionError::InvalidAccountData)
} }
@ -638,9 +639,9 @@ pub fn set_lockup(
meta.set_lockup(lockup, signers, clock)?; meta.set_lockup(lockup, signers, clock)?;
stake_account.set_state(&StakeState::Initialized(meta)) stake_account.set_state(&StakeState::Initialized(meta))
} }
StakeState::Stake(mut meta, stake) => { StakeState::Stake(mut meta, stake, stake_flags) => {
meta.set_lockup(lockup, signers, clock)?; meta.set_lockup(lockup, signers, clock)?;
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
} }
_ => Err(InstructionError::InvalidAccountData), _ => Err(InstructionError::InvalidAccountData),
} }
@ -677,7 +678,7 @@ pub fn split(
drop(stake_account); drop(stake_account);
match stake_state { match stake_state {
StakeState::Stake(meta, mut stake) => { StakeState::Stake(meta, mut stake, stake_flags) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?; meta.authorized.check(signers, StakeAuthorize::Staker)?;
let minimum_delegation = crate::get_minimum_delegation(&invoke_context.feature_set); let minimum_delegation = crate::get_minimum_delegation(&invoke_context.feature_set);
let validated_split_info = validate_split_amount( let validated_split_info = validate_split_amount(
@ -747,11 +748,11 @@ pub fn split(
let mut stake_account = instruction_context let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?; .try_borrow_instruction_account(transaction_context, stake_account_index)?;
stake_account.set_state(&StakeState::Stake(meta, stake))?; stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))?;
drop(stake_account); drop(stake_account);
let mut split = instruction_context let mut split = instruction_context
.try_borrow_instruction_account(transaction_context, split_index)?; .try_borrow_instruction_account(transaction_context, split_index)?;
split.set_state(&StakeState::Stake(split_meta, split_stake))?; split.set_state(&StakeState::Stake(split_meta, split_stake, stake_flags))?;
} }
StakeState::Initialized(meta) => { StakeState::Initialized(meta) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?; meta.authorized.check(signers, StakeAuthorize::Staker)?;
@ -927,7 +928,7 @@ pub fn redelegate(
let vote_state = vote_account.get_state::<VoteStateVersions>()?; let vote_state = vote_account.get_state::<VoteStateVersions>()?;
let (stake_meta, effective_stake) = let (stake_meta, effective_stake) =
if let StakeState::Stake(meta, stake) = stake_account.get_state()? { if let StakeState::Stake(meta, stake, _stake_flags) = stake_account.get_state()? {
let stake_history = invoke_context.get_sysvar_cache().get_stake_history()?; let stake_history = invoke_context.get_sysvar_cache().get_stake_history()?;
let status = stake let status = stake
.delegation .delegation
@ -983,6 +984,7 @@ pub fn redelegate(
clock.epoch, clock.epoch,
config, config,
), ),
StakeFlags::empty(),
))?; ))?;
Ok(()) Ok(())
@ -1013,7 +1015,7 @@ pub fn withdraw(
let mut stake_account = instruction_context let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?; .try_borrow_instruction_account(transaction_context, stake_account_index)?;
let (lockup, reserve, is_staked) = match stake_account.get_state()? { let (lockup, reserve, is_staked) = match stake_account.get_state()? {
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, _stake_flag) => {
meta.authorized meta.authorized
.check(&signers, StakeAuthorize::Withdrawer)?; .check(&signers, StakeAuthorize::Withdrawer)?;
// if we have a deactivation epoch and we're in cooldown // if we have a deactivation epoch and we're in cooldown
@ -1126,7 +1128,7 @@ pub(crate) fn deactivate_delinquent(
return Err(StakeError::InsufficientReferenceVotes.into()); return Err(StakeError::InsufficientReferenceVotes.into());
} }
if let StakeState::Stake(meta, mut stake) = stake_account.get_state()? { if let StakeState::Stake(meta, mut stake, stake_flags) = stake_account.get_state()? {
if stake.delegation.voter_pubkey != *delinquent_vote_account_pubkey { if stake.delegation.voter_pubkey != *delinquent_vote_account_pubkey {
return Err(StakeError::VoteAddressMismatch.into()); return Err(StakeError::VoteAddressMismatch.into());
} }
@ -1135,7 +1137,7 @@ pub(crate) fn deactivate_delinquent(
// voted in the last `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION` // voted in the last `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
if eligible_for_deactivate_delinquent(&delinquent_vote_state.epoch_credits, current_epoch) { if eligible_for_deactivate_delinquent(&delinquent_vote_state.epoch_credits, current_epoch) {
stake.deactivate(current_epoch)?; stake.deactivate(current_epoch)?;
stake_account.set_state(&StakeState::Stake(meta, stake)) stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
} else { } else {
Err(StakeError::MinimumDelinquentEpochsForDeactivationNotMet.into()) Err(StakeError::MinimumDelinquentEpochsForDeactivationNotMet.into())
} }
@ -1272,24 +1274,24 @@ fn validate_split_amount(
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum MergeKind { enum MergeKind {
Inactive(Meta, u64), Inactive(Meta, u64, StakeFlags),
ActivationEpoch(Meta, Stake), ActivationEpoch(Meta, Stake, StakeFlags),
FullyActive(Meta, Stake), FullyActive(Meta, Stake),
} }
impl MergeKind { impl MergeKind {
fn meta(&self) -> &Meta { fn meta(&self) -> &Meta {
match self { match self {
Self::Inactive(meta, _) => meta, Self::Inactive(meta, _, _) => meta,
Self::ActivationEpoch(meta, _) => meta, Self::ActivationEpoch(meta, _, _) => meta,
Self::FullyActive(meta, _) => meta, Self::FullyActive(meta, _) => meta,
} }
} }
fn active_stake(&self) -> Option<&Stake> { fn active_stake(&self) -> Option<&Stake> {
match self { match self {
Self::Inactive(_, _) => None, Self::Inactive(_, _, _) => None,
Self::ActivationEpoch(_, stake) => Some(stake), Self::ActivationEpoch(_, stake, _) => Some(stake),
Self::FullyActive(_, stake) => Some(stake), Self::FullyActive(_, stake) => Some(stake),
} }
} }
@ -1302,7 +1304,7 @@ impl MergeKind {
stake_history: &StakeHistory, stake_history: &StakeHistory,
) -> Result<Self, InstructionError> { ) -> Result<Self, InstructionError> {
match stake_state { match stake_state {
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, stake_flags) => {
// stake must not be in a transient state. Transient here meaning // stake must not be in a transient state. Transient here meaning
// activating or deactivating with non-zero effective stake. // activating or deactivating with non-zero effective stake.
let status = stake let status = stake
@ -1310,8 +1312,8 @@ impl MergeKind {
.stake_activating_and_deactivating(clock.epoch, Some(stake_history)); .stake_activating_and_deactivating(clock.epoch, Some(stake_history));
match (status.effective, status.activating, status.deactivating) { match (status.effective, status.activating, status.deactivating) {
(0, 0, 0) => Ok(Self::Inactive(*meta, stake_lamports)), (0, 0, 0) => Ok(Self::Inactive(*meta, stake_lamports, *stake_flags)),
(0, _, _) => Ok(Self::ActivationEpoch(*meta, *stake)), (0, _, _) => Ok(Self::ActivationEpoch(*meta, *stake, *stake_flags)),
(_, 0, 0) => Ok(Self::FullyActive(*meta, *stake)), (_, 0, 0) => Ok(Self::FullyActive(*meta, *stake)),
_ => { _ => {
let err = StakeError::MergeTransientStake; let err = StakeError::MergeTransientStake;
@ -1320,7 +1322,9 @@ impl MergeKind {
} }
} }
} }
StakeState::Initialized(meta) => Ok(Self::Inactive(*meta, stake_lamports)), StakeState::Initialized(meta) => {
Ok(Self::Inactive(*meta, stake_lamports, StakeFlags::empty()))
}
_ => Err(InstructionError::InvalidAccountData), _ => Err(InstructionError::InvalidAccountData),
} }
} }
@ -1414,15 +1418,22 @@ impl MergeKind {
}) })
.unwrap_or(Ok(()))?; .unwrap_or(Ok(()))?;
let merged_state = match (self, source) { let merged_state = match (self, source) {
(Self::Inactive(_, _), Self::Inactive(_, _)) => None, (Self::Inactive(_, _, _), Self::Inactive(_, _, _)) => None,
(Self::Inactive(_, _), Self::ActivationEpoch(_, _)) => None, (Self::Inactive(_, _, _), Self::ActivationEpoch(_, _, _)) => None,
(Self::ActivationEpoch(meta, mut stake), Self::Inactive(_, source_lamports)) => { (
Self::ActivationEpoch(meta, mut stake, stake_flags),
Self::Inactive(_, source_lamports, source_stake_flags),
) => {
stake.delegation.stake = checked_add(stake.delegation.stake, source_lamports)?; stake.delegation.stake = checked_add(stake.delegation.stake, source_lamports)?;
Some(StakeState::Stake(meta, stake)) Some(StakeState::Stake(
meta,
stake,
stake_flags.union(source_stake_flags),
))
} }
( (
Self::ActivationEpoch(meta, mut stake), Self::ActivationEpoch(meta, mut stake, stake_flags),
Self::ActivationEpoch(source_meta, source_stake), Self::ActivationEpoch(source_meta, source_stake, source_stake_flags),
) => { ) => {
let source_lamports = checked_add( let source_lamports = checked_add(
source_meta.rent_exempt_reserve, source_meta.rent_exempt_reserve,
@ -1434,7 +1445,11 @@ impl MergeKind {
source_lamports, source_lamports,
source_stake.credits_observed, source_stake.credits_observed,
)?; )?;
Some(StakeState::Stake(meta, stake)) Some(StakeState::Stake(
meta,
stake,
stake_flags.union(source_stake_flags),
))
} }
(Self::FullyActive(meta, mut stake), Self::FullyActive(_, source_stake)) => { (Self::FullyActive(meta, mut stake), Self::FullyActive(_, source_stake)) => {
// Don't stake the source account's `rent_exempt_reserve` to // Don't stake the source account's `rent_exempt_reserve` to
@ -1447,7 +1462,7 @@ impl MergeKind {
source_stake.delegation.stake, source_stake.delegation.stake,
source_stake.credits_observed, source_stake.credits_observed,
)?; )?;
Some(StakeState::Stake(meta, stake)) Some(StakeState::Stake(meta, stake, StakeFlags::empty()))
} }
_ => return Err(StakeError::MergeMismatch.into()), _ => return Err(StakeError::MergeMismatch.into()),
}; };
@ -1533,7 +1548,7 @@ pub fn redeem_rewards(
stake_history: Option<&StakeHistory>, stake_history: Option<&StakeHistory>,
inflation_point_calc_tracer: Option<impl Fn(&InflationPointCalculationEvent)>, inflation_point_calc_tracer: Option<impl Fn(&InflationPointCalculationEvent)>,
) -> Result<(u64, u64), InstructionError> { ) -> Result<(u64, u64), InstructionError> {
if let StakeState::Stake(meta, mut stake) = stake_state { if let StakeState::Stake(meta, mut stake, stake_flags) = stake_state {
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer.as_ref() { if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer.as_ref() {
inflation_point_calc_tracer( inflation_point_calc_tracer(
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch( &InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(
@ -1557,7 +1572,7 @@ pub fn redeem_rewards(
inflation_point_calc_tracer, inflation_point_calc_tracer,
) { ) {
stake_account.checked_add_lamports(stakers_reward)?; stake_account.checked_add_lamports(stakers_reward)?;
stake_account.set_state(&StakeState::Stake(meta, stake))?; stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))?;
Ok((stakers_reward, voters_reward)) Ok((stakers_reward, voters_reward))
} else { } else {
@ -1575,7 +1590,7 @@ pub fn calculate_points(
vote_state: &VoteState, vote_state: &VoteState,
stake_history: Option<&StakeHistory>, stake_history: Option<&StakeHistory>,
) -> Result<u128, InstructionError> { ) -> Result<u128, InstructionError> {
if let StakeState::Stake(_meta, stake) = stake_state { if let StakeState::Stake(_meta, stake, _stake_flags) = stake_state {
Ok(calculate_stake_points( Ok(calculate_stake_points(
stake, stake,
vote_state, vote_state,
@ -1724,6 +1739,7 @@ fn do_create_account(
activation_epoch, activation_epoch,
&Config::default(), &Config::default(),
), ),
StakeFlags::empty(),
)) ))
.expect("set_state"); .expect("set_state");
@ -3221,7 +3237,7 @@ mod tests {
&stake_history &stake_history
) )
.unwrap(), .unwrap(),
MergeKind::Inactive(meta, stake_lamports) MergeKind::Inactive(meta, stake_lamports, StakeFlags::empty())
); );
clock.epoch = 0; clock.epoch = 0;
@ -3258,7 +3274,7 @@ mod tests {
..Stake::default() ..Stake::default()
}; };
stake_account stake_account
.set_state(&StakeState::Stake(meta, stake)) .set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
.unwrap(); .unwrap();
// activation_epoch succeeds // activation_epoch succeeds
assert_eq!( assert_eq!(
@ -3270,7 +3286,7 @@ mod tests {
&stake_history &stake_history
) )
.unwrap(), .unwrap(),
MergeKind::ActivationEpoch(meta, stake), MergeKind::ActivationEpoch(meta, stake, StakeFlags::empty()),
); );
// all paritially activated, transient epochs fail // all paritially activated, transient epochs fail
@ -3392,7 +3408,7 @@ mod tests {
&stake_history &stake_history
) )
.unwrap(), .unwrap(),
MergeKind::Inactive(meta, stake_lamports), MergeKind::Inactive(meta, stake_lamports, StakeFlags::empty()),
); );
} }
@ -3412,8 +3428,8 @@ mod tests {
}, },
..Stake::default() ..Stake::default()
}; };
let inactive = MergeKind::Inactive(Meta::default(), lamports); let inactive = MergeKind::Inactive(Meta::default(), lamports, StakeFlags::empty());
let activation_epoch = MergeKind::ActivationEpoch(meta, stake); let activation_epoch = MergeKind::ActivationEpoch(meta, stake, StakeFlags::empty());
let fully_active = MergeKind::FullyActive(meta, stake); let fully_active = MergeKind::FullyActive(meta, stake);
assert_eq!( assert_eq!(
@ -3507,8 +3523,8 @@ mod tests {
}; };
// activating stake merge, match credits observed // activating stake merge, match credits observed
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a); let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a, StakeFlags::empty());
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b); let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b, StakeFlags::empty());
let new_stake = activation_epoch_a let new_stake = activation_epoch_a
.merge(&invoke_context, activation_epoch_b, &clock) .merge(&invoke_context, activation_epoch_b, &clock)
.unwrap() .unwrap()
@ -3542,8 +3558,8 @@ mod tests {
}, },
credits_observed: credits_b, credits_observed: credits_b,
}; };
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a); let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a, StakeFlags::empty());
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b); let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b, StakeFlags::empty());
let new_stake = activation_epoch_a let new_stake = activation_epoch_a
.merge(&invoke_context, activation_epoch_b, &clock) .merge(&invoke_context, activation_epoch_b, &clock)
.unwrap() .unwrap()

View File

@ -60,7 +60,7 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> ScanResult<NonCircu
non_circulating_accounts_set.insert(*pubkey); non_circulating_accounts_set.insert(*pubkey);
} }
} }
StakeState::Stake(meta, _stake) => { StakeState::Stake(meta, _stake, _stake_flags) => {
if meta.lockup.is_in_force(&clock, None) if meta.lockup.is_in_force(&clock, None)
|| withdraw_authority_list.contains(&meta.authorized.withdrawer) || withdraw_authority_list.contains(&meta.authorized.withdrawer)
{ {

View File

@ -110,11 +110,15 @@ impl AbiExample for StakeAccount<Delegation> {
fn example() -> Self { fn example() -> Self {
use solana_sdk::{ use solana_sdk::{
account::Account, account::Account,
stake::state::{Meta, Stake}, stake::{
stake_flags::StakeFlags,
state::{Meta, Stake},
},
}; };
let stake_state = StakeState::Stake(Meta::example(), Stake::example()); let stake_state =
StakeState::Stake(Meta::example(), Stake::example(), StakeFlags::example());
let mut account = Account::example(); let mut account = Account::example();
account.data.resize(196, 0u8); account.data.resize(200, 0u8);
account.owner = solana_stake_program::id(); account.owner = solana_stake_program::id();
account.set_state(&stake_state).unwrap(); account.set_state(&stake_state).unwrap();
Self::try_from(AccountSharedData::from(account)).unwrap() Self::try_from(AccountSharedData::from(account)).unwrap()

View File

@ -362,7 +362,7 @@ fn test_stake_account_lifetime() {
// Test that correct lamports are staked // Test that correct lamports are staked
let account = bank.get_account(&stake_pubkey).expect("account not found"); let account = bank.get_account(&stake_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data"); let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(_meta, stake) = stake_state { if let StakeState::Stake(_meta, stake, _stake_flags) = stake_state {
assert_eq!(stake.delegation.stake, stake_starting_delegation,); assert_eq!(stake.delegation.stake, stake_starting_delegation,);
} else { } else {
panic!("wrong account type found") panic!("wrong account type found")
@ -386,7 +386,7 @@ fn test_stake_account_lifetime() {
// Test that lamports are still staked // Test that lamports are still staked
let account = bank.get_account(&stake_pubkey).expect("account not found"); let account = bank.get_account(&stake_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data"); let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(_meta, stake) = stake_state { if let StakeState::Stake(_meta, stake, _stake_flags) = stake_state {
assert_eq!(stake.delegation.stake, stake_starting_delegation,); assert_eq!(stake.delegation.stake, stake_starting_delegation,);
} else { } else {
panic!("wrong account type found") panic!("wrong account type found")
@ -636,7 +636,7 @@ fn test_create_stake_account_from_seed() {
// Test that correct lamports are staked // Test that correct lamports are staked
let account = bank.get_account(&stake_pubkey).expect("account not found"); let account = bank.get_account(&stake_pubkey).expect("account not found");
let stake_state = account.state().expect("couldn't unpack account data"); let stake_state = account.state().expect("couldn't unpack account data");
if let StakeState::Stake(_meta, stake) = stake_state { if let StakeState::Stake(_meta, stake, _) = stake_state {
assert_eq!(stake.delegation.stake, delegation); assert_eq!(stake.delegation.stake, delegation);
} else { } else {
panic!("wrong account type found") panic!("wrong account type found")

View File

@ -7,6 +7,7 @@ use {
stake::{ stake::{
config::Config, config::Config,
instruction::{LockupArgs, StakeError}, instruction::{LockupArgs, StakeError},
stake_flags::StakeFlags,
}, },
stake_history::{StakeHistory, StakeHistoryEntry}, stake_history::{StakeHistory, StakeHistoryEntry},
}, },
@ -22,7 +23,7 @@ pub enum StakeState {
#[default] #[default]
Uninitialized, Uninitialized,
Initialized(Meta), Initialized(Meta),
Stake(Meta, Stake), Stake(Meta, Stake, StakeFlags),
RewardsPool, RewardsPool,
} }
@ -36,9 +37,10 @@ impl BorshDeserialize for StakeState {
Ok(StakeState::Initialized(meta)) Ok(StakeState::Initialized(meta))
} }
2 => { 2 => {
let meta = Meta::deserialize_reader(reader)?; let meta: Meta = BorshDeserialize::deserialize_reader(reader)?;
let stake = Stake::deserialize_reader(reader)?; let stake: Stake = BorshDeserialize::deserialize_reader(reader)?;
Ok(StakeState::Stake(meta, stake)) let stake_flags: StakeFlags = BorshDeserialize::deserialize_reader(reader)?;
Ok(StakeState::Stake(meta, stake, stake_flags))
} }
3 => Ok(StakeState::RewardsPool), 3 => Ok(StakeState::RewardsPool),
_ => Err(io::Error::new( _ => Err(io::Error::new(
@ -57,10 +59,11 @@ impl BorshSerialize for StakeState {
writer.write_all(&1u32.to_le_bytes())?; writer.write_all(&1u32.to_le_bytes())?;
meta.serialize(writer) meta.serialize(writer)
} }
StakeState::Stake(meta, stake) => { StakeState::Stake(meta, stake, stake_flags) => {
writer.write_all(&2u32.to_le_bytes())?; writer.write_all(&2u32.to_le_bytes())?;
meta.serialize(writer)?; meta.serialize(writer)?;
stake.serialize(writer) stake.serialize(writer)?;
stake_flags.serialize(writer)
} }
StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()), StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()),
} }
@ -75,21 +78,21 @@ impl StakeState {
pub fn stake(&self) -> Option<Stake> { pub fn stake(&self) -> Option<Stake> {
match self { match self {
StakeState::Stake(_meta, stake) => Some(*stake), StakeState::Stake(_meta, stake, _stake_flags) => Some(*stake),
_ => None, _ => None,
} }
} }
pub fn delegation(&self) -> Option<Delegation> { pub fn delegation(&self) -> Option<Delegation> {
match self { match self {
StakeState::Stake(_meta, stake) => Some(stake.delegation), StakeState::Stake(_meta, stake, _stake_flags) => Some(stake.delegation),
_ => None, _ => None,
} }
} }
pub fn authorized(&self) -> Option<Authorized> { pub fn authorized(&self) -> Option<Authorized> {
match self { match self {
StakeState::Stake(meta, _stake) => Some(meta.authorized), StakeState::Stake(meta, _stake, _stake_flags) => Some(meta.authorized),
StakeState::Initialized(meta) => Some(meta.authorized), StakeState::Initialized(meta) => Some(meta.authorized),
_ => None, _ => None,
} }
@ -101,7 +104,7 @@ impl StakeState {
pub fn meta(&self) -> Option<Meta> { pub fn meta(&self) -> Option<Meta> {
match self { match self {
StakeState::Stake(meta, _stake) => Some(*meta), StakeState::Stake(meta, _stake, _stake_flags) => Some(*meta),
StakeState::Initialized(meta) => Some(*meta), StakeState::Initialized(meta) => Some(*meta),
_ => None, _ => None,
} }
@ -629,6 +632,7 @@ mod test {
}, },
credits_observed: 1, credits_observed: 1,
}, },
StakeFlags::empty(),
)); ));
} }
@ -663,6 +667,7 @@ mod test {
}, },
credits_observed: 1, credits_observed: 1,
}, },
StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
)); ));
} }