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:
parent
8e5805797e
commit
17af3ab10a
|
@ -19,7 +19,7 @@ pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
|
|||
meta: meta.into(),
|
||||
stake: None,
|
||||
}),
|
||||
StakeState::Stake(meta, stake) => StakeAccountType::Delegated(UiStakeAccount {
|
||||
StakeState::Stake(meta, stake, _) => StakeAccountType::Delegated(UiStakeAccount {
|
||||
meta: meta.into(),
|
||||
stake: Some(stake.into()),
|
||||
}),
|
||||
|
@ -136,7 +136,7 @@ impl From<Delegation> for UiDelegation {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {super::*, bincode::serialize};
|
||||
use {super::*, bincode::serialize, solana_sdk::stake::stake_flags::StakeFlags};
|
||||
|
||||
#[test]
|
||||
fn test_parse_stake() {
|
||||
|
@ -194,7 +194,7 @@ mod test {
|
|||
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();
|
||||
assert_eq!(
|
||||
parse_stake(&stake_data).unwrap(),
|
||||
|
|
|
@ -1819,7 +1819,7 @@ pub fn process_show_stakes(
|
|||
});
|
||||
}
|
||||
}
|
||||
StakeState::Stake(_, stake) => {
|
||||
StakeState::Stake(_, stake, _) => {
|
||||
if vote_account_pubkeys.is_none()
|
||||
|| vote_account_pubkeys
|
||||
.unwrap()
|
||||
|
|
|
@ -1628,7 +1628,7 @@ pub fn process_deactivate_stake_account(
|
|||
|
||||
let vote_account_address = match stake_account.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!(
|
||||
"{stake_account_address} is not a delegated stake account",
|
||||
|
@ -2195,6 +2195,7 @@ pub fn build_stake_state(
|
|||
lockup,
|
||||
},
|
||||
stake,
|
||||
_,
|
||||
) => {
|
||||
let current_epoch = clock.epoch;
|
||||
let StakeActivationStatus {
|
||||
|
|
|
@ -165,7 +165,7 @@ fn test_stake_redelegation() {
|
|||
let stake_state: StakeState = stake_account.state().unwrap();
|
||||
|
||||
let rent_exempt_reserve = match stake_state {
|
||||
StakeState::Stake(meta, stake) => {
|
||||
StakeState::Stake(meta, stake, _) => {
|
||||
assert_eq!(stake.delegation.voter_pubkey, vote_keypair.pubkey());
|
||||
meta.rent_exempt_reserve
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ fn test_stake_redelegation() {
|
|||
let stake2_state: StakeState = stake2_account.state().unwrap();
|
||||
|
||||
match stake2_state {
|
||||
StakeState::Stake(_meta, stake) => {
|
||||
StakeState::Stake(_meta, stake, _) => {
|
||||
assert_eq!(stake.delegation.voter_pubkey, vote2_keypair.pubkey());
|
||||
}
|
||||
_ => panic!("Unexpected stake2 state!"),
|
||||
|
|
|
@ -2965,7 +2965,7 @@ fn main() {
|
|||
.unwrap()
|
||||
.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
|
||||
.contains(&stake.delegation.voter_pubkey)
|
||||
{
|
||||
|
|
|
@ -481,6 +481,7 @@ mod tests {
|
|||
set_lockup_checked, AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs,
|
||||
LockupArgs, StakeError,
|
||||
},
|
||||
stake_flags::StakeFlags,
|
||||
state::{Authorized, Lockup, StakeActivationStatus, StakeAuthorize},
|
||||
MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION,
|
||||
},
|
||||
|
@ -610,6 +611,7 @@ mod tests {
|
|||
},
|
||||
..Stake::default()
|
||||
},
|
||||
StakeFlags::empty(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2721,7 +2723,7 @@ mod tests {
|
|||
StakeState::Initialized(_meta) => {
|
||||
assert_eq!(from(&accounts[0]).unwrap(), state);
|
||||
}
|
||||
StakeState::Stake(_meta, _stake) => {
|
||||
StakeState::Stake(_meta, _stake, _) => {
|
||||
let stake_0 = from(&accounts[0]).unwrap().stake();
|
||||
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
|
||||
// make the destination rent exempt, and then the leftover lamports are delegated.
|
||||
if expected_result.is_ok() {
|
||||
assert_matches!(accounts[0].state().unwrap(), StakeState::Stake(_, _));
|
||||
if let StakeState::Stake(_, destination_stake) = accounts[1].state().unwrap() {
|
||||
assert_matches!(accounts[0].state().unwrap(), StakeState::Stake(_, _, _));
|
||||
if let StakeState::Stake(_, destination_stake, _) = accounts[1].state().unwrap() {
|
||||
let destination_initial_rent_deficit =
|
||||
rent_exempt_reserve.saturating_sub(destination_starting_balance);
|
||||
let expected_destination_stake_delegation =
|
||||
|
@ -4737,7 +4739,7 @@ mod tests {
|
|||
|
||||
for split_to_state in &[
|
||||
StakeState::Initialized(Meta::default()),
|
||||
StakeState::Stake(Meta::default(), Stake::default()),
|
||||
StakeState::Stake(Meta::default(), Stake::default(), StakeFlags::default()),
|
||||
StakeState::RewardsPool,
|
||||
] {
|
||||
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
|
||||
if let StakeState::Stake(meta, stake) = state {
|
||||
if let StakeState::Stake(meta, stake, stake_flags) = state {
|
||||
assert_eq!(
|
||||
accounts[1].state(),
|
||||
Ok(StakeState::Stake(
|
||||
|
@ -4914,7 +4916,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..*stake
|
||||
}
|
||||
},
|
||||
*stake_flags,
|
||||
))
|
||||
);
|
||||
assert_eq!(accounts[0].lamports(), *minimum_balance,);
|
||||
|
@ -5005,7 +5008,7 @@ mod tests {
|
|||
stake_lamports + initial_balance,
|
||||
);
|
||||
|
||||
if let StakeState::Stake(meta, stake) = state {
|
||||
if let StakeState::Stake(meta, stake, stake_flags) = state {
|
||||
let expected_stake =
|
||||
stake_lamports / 2 - (rent_exempt_reserve.saturating_sub(initial_balance));
|
||||
assert_eq!(
|
||||
|
@ -5018,7 +5021,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..stake
|
||||
}
|
||||
},
|
||||
stake_flags
|
||||
)),
|
||||
accounts[1].state(),
|
||||
);
|
||||
|
@ -5037,7 +5041,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..stake
|
||||
}
|
||||
},
|
||||
stake_flags,
|
||||
)),
|
||||
accounts[0].state(),
|
||||
);
|
||||
|
@ -5128,7 +5133,7 @@ mod tests {
|
|||
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 {
|
||||
authorized: Authorized::auto(&stake_address),
|
||||
rent_exempt_reserve: split_rent_exempt_reserve,
|
||||
|
@ -5146,7 +5151,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..stake
|
||||
}
|
||||
},
|
||||
stake_flags,
|
||||
)),
|
||||
accounts[1].state()
|
||||
);
|
||||
|
@ -5165,7 +5171,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..stake
|
||||
}
|
||||
},
|
||||
stake_flags,
|
||||
)),
|
||||
accounts[0].state()
|
||||
);
|
||||
|
@ -5321,7 +5328,7 @@ mod tests {
|
|||
assert_eq!(Ok(*state), accounts[1].state());
|
||||
assert_eq!(Ok(StakeState::Uninitialized), accounts[0].state());
|
||||
}
|
||||
StakeState::Stake(meta, stake) => {
|
||||
StakeState::Stake(meta, stake, stake_flags) => {
|
||||
assert_eq!(
|
||||
Ok(StakeState::Stake(
|
||||
*meta,
|
||||
|
@ -5331,7 +5338,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..*stake
|
||||
}
|
||||
},
|
||||
*stake_flags
|
||||
)),
|
||||
accounts[1].state()
|
||||
);
|
||||
|
@ -5416,7 +5424,7 @@ mod tests {
|
|||
stake_lamports + initial_balance
|
||||
);
|
||||
|
||||
if let StakeState::Stake(meta, stake) = state {
|
||||
if let StakeState::Stake(meta, stake, stake_flags) = state {
|
||||
assert_eq!(
|
||||
Ok(StakeState::Stake(
|
||||
meta,
|
||||
|
@ -5426,7 +5434,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..stake
|
||||
}
|
||||
},
|
||||
stake_flags,
|
||||
)),
|
||||
accounts[1].state()
|
||||
);
|
||||
|
@ -5538,7 +5547,7 @@ mod tests {
|
|||
);
|
||||
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
|
||||
// from the rent_exempt_reserve inequality do not magically activate
|
||||
let expected_stake = stake_lamports - source_rent_exempt_reserve;
|
||||
|
@ -5552,7 +5561,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..*stake
|
||||
}
|
||||
},
|
||||
*stake_flags,
|
||||
)),
|
||||
accounts[1].state()
|
||||
);
|
||||
|
@ -5667,7 +5677,7 @@ mod tests {
|
|||
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
|
||||
+ merge_from_state
|
||||
.stake()
|
||||
|
@ -5686,7 +5696,8 @@ mod tests {
|
|||
..stake.delegation
|
||||
},
|
||||
..*stake
|
||||
}
|
||||
},
|
||||
*stake_flags,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
@ -5720,7 +5731,7 @@ mod tests {
|
|||
};
|
||||
let stake_account = AccountSharedData::new_data_with_space(
|
||||
stake_lamports,
|
||||
&StakeState::Stake(meta, stake),
|
||||
&StakeState::Stake(meta, stake, StakeFlags::empty()),
|
||||
StakeState::size_of(),
|
||||
&id(),
|
||||
)
|
||||
|
@ -6047,7 +6058,7 @@ mod tests {
|
|||
};
|
||||
let stake_account = AccountSharedData::new_data_with_space(
|
||||
stake_lamports,
|
||||
&StakeState::Stake(meta, stake),
|
||||
&StakeState::Stake(meta, stake, StakeFlags::empty()),
|
||||
StakeState::size_of(),
|
||||
&id(),
|
||||
)
|
||||
|
@ -6063,7 +6074,7 @@ mod tests {
|
|||
};
|
||||
let merge_from_account = AccountSharedData::new_data_with_space(
|
||||
merge_from_lamports,
|
||||
&StakeState::Stake(meta, merge_from_stake),
|
||||
&StakeState::Stake(meta, merge_from_stake, StakeFlags::empty()),
|
||||
StakeState::size_of(),
|
||||
&id(),
|
||||
)
|
||||
|
@ -6219,7 +6230,7 @@ mod tests {
|
|||
};
|
||||
transaction_accounts[0]
|
||||
.1
|
||||
.set_state(&StakeState::Stake(meta, stake))
|
||||
.set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
|
||||
.unwrap();
|
||||
}
|
||||
if clock.epoch == merge_from_deactivation_epoch {
|
||||
|
@ -6233,7 +6244,11 @@ mod tests {
|
|||
};
|
||||
transaction_accounts[1]
|
||||
.1
|
||||
.set_state(&StakeState::Stake(meta, merge_from_stake))
|
||||
.set_state(&StakeState::Stake(
|
||||
meta,
|
||||
merge_from_stake,
|
||||
StakeFlags::empty(),
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
stake_history.add(
|
||||
|
@ -6394,6 +6409,7 @@ mod tests {
|
|||
1, /* activation_epoch */
|
||||
&stake_config::Config::default(),
|
||||
),
|
||||
StakeFlags::empty(),
|
||||
);
|
||||
|
||||
let stake_account = AccountSharedData::new_data_with_space(
|
||||
|
@ -6593,6 +6609,7 @@ mod tests {
|
|||
1, /* activation_epoch */
|
||||
&stake_config::Config::default(),
|
||||
),
|
||||
StakeFlags::empty(),
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
|
@ -6686,6 +6703,7 @@ mod tests {
|
|||
activation_epoch,
|
||||
&stake_config::Config::default(),
|
||||
),
|
||||
StakeFlags::empty(),
|
||||
);
|
||||
|
||||
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);
|
||||
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!(
|
||||
stake.delegation.stake,
|
||||
|
@ -6831,7 +6849,7 @@ mod tests {
|
|||
output_accounts[1].lamports(),
|
||||
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!(stake.delegation.stake, minimum_delegation);
|
||||
assert_eq!(stake.delegation.activation_epoch, current_epoch);
|
||||
|
@ -6974,7 +6992,7 @@ mod tests {
|
|||
output_accounts[1].lamports(),
|
||||
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!(stake.delegation.stake, minimum_delegation + 42);
|
||||
assert_eq!(stake.delegation.activation_epoch, current_epoch);
|
||||
|
@ -6988,12 +7006,12 @@ mod tests {
|
|||
//
|
||||
let mut stake_account_over_allocated =
|
||||
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()
|
||||
{
|
||||
meta.rent_exempt_reserve += 42;
|
||||
stake_account_over_allocated
|
||||
.set_state(&StakeState::Stake(meta, stake))
|
||||
.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
.unwrap();
|
||||
}
|
||||
stake_account_over_allocated
|
||||
|
@ -7016,7 +7034,7 @@ mod tests {
|
|||
);
|
||||
|
||||
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);
|
||||
} else {
|
||||
panic!("Invalid output_accounts[0] data");
|
||||
|
@ -7025,7 +7043,7 @@ mod tests {
|
|||
output_accounts[1].lamports(),
|
||||
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!(stake.delegation.stake, minimum_delegation);
|
||||
} else {
|
||||
|
@ -7163,7 +7181,7 @@ mod tests {
|
|||
|
||||
let mut deactivating_stake_account =
|
||||
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()
|
||||
{
|
||||
stake.deactivate(current_epoch).unwrap();
|
||||
|
@ -7179,7 +7197,7 @@ mod tests {
|
|||
);
|
||||
|
||||
deactivating_stake_account
|
||||
.set_state(&StakeState::Stake(meta, stake))
|
||||
.set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
|
||||
.unwrap();
|
||||
}
|
||||
let _ = process_instruction_redelegate(
|
||||
|
@ -7198,7 +7216,7 @@ mod tests {
|
|||
// (less than `minimum_delegation + rent_exempt_reserve`)
|
||||
//
|
||||
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.delegation.stake -= 1;
|
||||
|
@ -7207,7 +7225,7 @@ mod tests {
|
|||
minimum_delegation + rent_exempt_reserve - 1
|
||||
);
|
||||
stake_account_too_few_lamports
|
||||
.set_state(&StakeState::Stake(meta, stake))
|
||||
.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
.unwrap();
|
||||
} else {
|
||||
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(
|
||||
&stake_address,
|
||||
|
|
|
@ -25,6 +25,7 @@ use {
|
|||
config::Config,
|
||||
instruction::{LockupArgs, StakeError},
|
||||
program::id,
|
||||
stake_flags::StakeFlags,
|
||||
tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent},
|
||||
},
|
||||
stake_history::{StakeHistory, StakeHistoryEntry},
|
||||
|
@ -487,7 +488,7 @@ pub fn authorize(
|
|||
custodian: Option<&Pubkey>,
|
||||
) -> Result<(), InstructionError> {
|
||||
match stake_account.get_state()? {
|
||||
StakeState::Stake(mut meta, stake) => {
|
||||
StakeState::Stake(mut meta, stake, stake_flags) => {
|
||||
meta.authorized.authorize(
|
||||
signers,
|
||||
new_authority,
|
||||
|
@ -498,7 +499,7 @@ pub fn authorize(
|
|||
None
|
||||
},
|
||||
)?;
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake))
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
}
|
||||
StakeState::Initialized(mut meta) => {
|
||||
meta.authorized.authorize(
|
||||
|
@ -590,9 +591,9 @@ pub fn delegate(
|
|||
clock.epoch,
|
||||
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)?;
|
||||
let ValidatedDelegatedInfo { stake_amount } =
|
||||
validate_delegated_amount(&stake_account, &meta, feature_set)?;
|
||||
|
@ -606,7 +607,7 @@ pub fn delegate(
|
|||
stake_history,
|
||||
config,
|
||||
)?;
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake))
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
}
|
||||
_ => Err(InstructionError::InvalidAccountData),
|
||||
}
|
||||
|
@ -617,11 +618,11 @@ pub fn deactivate(
|
|||
clock: &Clock,
|
||||
signers: &HashSet<Pubkey>,
|
||||
) -> 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)?;
|
||||
stake.deactivate(clock.epoch)?;
|
||||
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake))
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
} else {
|
||||
Err(InstructionError::InvalidAccountData)
|
||||
}
|
||||
|
@ -638,9 +639,9 @@ pub fn set_lockup(
|
|||
meta.set_lockup(lockup, signers, clock)?;
|
||||
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)?;
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake))
|
||||
stake_account.set_state(&StakeState::Stake(meta, stake, stake_flags))
|
||||
}
|
||||
_ => Err(InstructionError::InvalidAccountData),
|
||||
}
|
||||
|
@ -677,7 +678,7 @@ pub fn split(
|
|||
drop(stake_account);
|
||||
|
||||
match stake_state {
|
||||
StakeState::Stake(meta, mut stake) => {
|
||||
StakeState::Stake(meta, mut stake, stake_flags) => {
|
||||
meta.authorized.check(signers, StakeAuthorize::Staker)?;
|
||||
let minimum_delegation = crate::get_minimum_delegation(&invoke_context.feature_set);
|
||||
let validated_split_info = validate_split_amount(
|
||||
|
@ -747,11 +748,11 @@ pub fn split(
|
|||
|
||||
let mut stake_account = instruction_context
|
||||
.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);
|
||||
let mut split = instruction_context
|
||||
.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) => {
|
||||
meta.authorized.check(signers, StakeAuthorize::Staker)?;
|
||||
|
@ -927,7 +928,7 @@ pub fn redelegate(
|
|||
let vote_state = vote_account.get_state::<VoteStateVersions>()?;
|
||||
|
||||
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 status = stake
|
||||
.delegation
|
||||
|
@ -983,6 +984,7 @@ pub fn redelegate(
|
|||
clock.epoch,
|
||||
config,
|
||||
),
|
||||
StakeFlags::empty(),
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1013,7 +1015,7 @@ pub fn withdraw(
|
|||
let mut stake_account = instruction_context
|
||||
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
|
||||
let (lockup, reserve, is_staked) = match stake_account.get_state()? {
|
||||
StakeState::Stake(meta, stake) => {
|
||||
StakeState::Stake(meta, stake, _stake_flag) => {
|
||||
meta.authorized
|
||||
.check(&signers, StakeAuthorize::Withdrawer)?;
|
||||
// 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());
|
||||
}
|
||||
|
||||
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 {
|
||||
return Err(StakeError::VoteAddressMismatch.into());
|
||||
}
|
||||
|
@ -1135,7 +1137,7 @@ pub(crate) fn deactivate_delinquent(
|
|||
// voted in the last `MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION`
|
||||
if eligible_for_deactivate_delinquent(&delinquent_vote_state.epoch_credits, 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 {
|
||||
Err(StakeError::MinimumDelinquentEpochsForDeactivationNotMet.into())
|
||||
}
|
||||
|
@ -1272,24 +1274,24 @@ fn validate_split_amount(
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum MergeKind {
|
||||
Inactive(Meta, u64),
|
||||
ActivationEpoch(Meta, Stake),
|
||||
Inactive(Meta, u64, StakeFlags),
|
||||
ActivationEpoch(Meta, Stake, StakeFlags),
|
||||
FullyActive(Meta, Stake),
|
||||
}
|
||||
|
||||
impl MergeKind {
|
||||
fn meta(&self) -> &Meta {
|
||||
match self {
|
||||
Self::Inactive(meta, _) => meta,
|
||||
Self::ActivationEpoch(meta, _) => meta,
|
||||
Self::Inactive(meta, _, _) => meta,
|
||||
Self::ActivationEpoch(meta, _, _) => meta,
|
||||
Self::FullyActive(meta, _) => meta,
|
||||
}
|
||||
}
|
||||
|
||||
fn active_stake(&self) -> Option<&Stake> {
|
||||
match self {
|
||||
Self::Inactive(_, _) => None,
|
||||
Self::ActivationEpoch(_, stake) => Some(stake),
|
||||
Self::Inactive(_, _, _) => None,
|
||||
Self::ActivationEpoch(_, stake, _) => Some(stake),
|
||||
Self::FullyActive(_, stake) => Some(stake),
|
||||
}
|
||||
}
|
||||
|
@ -1302,7 +1304,7 @@ impl MergeKind {
|
|||
stake_history: &StakeHistory,
|
||||
) -> Result<Self, InstructionError> {
|
||||
match stake_state {
|
||||
StakeState::Stake(meta, stake) => {
|
||||
StakeState::Stake(meta, stake, stake_flags) => {
|
||||
// stake must not be in a transient state. Transient here meaning
|
||||
// activating or deactivating with non-zero effective stake.
|
||||
let status = stake
|
||||
|
@ -1310,8 +1312,8 @@ impl MergeKind {
|
|||
.stake_activating_and_deactivating(clock.epoch, Some(stake_history));
|
||||
|
||||
match (status.effective, status.activating, status.deactivating) {
|
||||
(0, 0, 0) => Ok(Self::Inactive(*meta, stake_lamports)),
|
||||
(0, _, _) => Ok(Self::ActivationEpoch(*meta, *stake)),
|
||||
(0, 0, 0) => Ok(Self::Inactive(*meta, stake_lamports, *stake_flags)),
|
||||
(0, _, _) => Ok(Self::ActivationEpoch(*meta, *stake, *stake_flags)),
|
||||
(_, 0, 0) => Ok(Self::FullyActive(*meta, *stake)),
|
||||
_ => {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -1414,15 +1418,22 @@ impl MergeKind {
|
|||
})
|
||||
.unwrap_or(Ok(()))?;
|
||||
let merged_state = match (self, source) {
|
||||
(Self::Inactive(_, _), Self::Inactive(_, _)) => None,
|
||||
(Self::Inactive(_, _), Self::ActivationEpoch(_, _)) => None,
|
||||
(Self::ActivationEpoch(meta, mut stake), Self::Inactive(_, source_lamports)) => {
|
||||
(Self::Inactive(_, _, _), Self::Inactive(_, _, _)) => None,
|
||||
(Self::Inactive(_, _, _), Self::ActivationEpoch(_, _, _)) => None,
|
||||
(
|
||||
Self::ActivationEpoch(meta, mut stake, stake_flags),
|
||||
Self::Inactive(_, source_lamports, source_stake_flags),
|
||||
) => {
|
||||
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(source_meta, source_stake),
|
||||
Self::ActivationEpoch(meta, mut stake, stake_flags),
|
||||
Self::ActivationEpoch(source_meta, source_stake, source_stake_flags),
|
||||
) => {
|
||||
let source_lamports = checked_add(
|
||||
source_meta.rent_exempt_reserve,
|
||||
|
@ -1434,7 +1445,11 @@ impl MergeKind {
|
|||
source_lamports,
|
||||
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)) => {
|
||||
// Don't stake the source account's `rent_exempt_reserve` to
|
||||
|
@ -1447,7 +1462,7 @@ impl MergeKind {
|
|||
source_stake.delegation.stake,
|
||||
source_stake.credits_observed,
|
||||
)?;
|
||||
Some(StakeState::Stake(meta, stake))
|
||||
Some(StakeState::Stake(meta, stake, StakeFlags::empty()))
|
||||
}
|
||||
_ => return Err(StakeError::MergeMismatch.into()),
|
||||
};
|
||||
|
@ -1533,7 +1548,7 @@ pub fn redeem_rewards(
|
|||
stake_history: Option<&StakeHistory>,
|
||||
inflation_point_calc_tracer: Option<impl Fn(&InflationPointCalculationEvent)>,
|
||||
) -> 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() {
|
||||
inflation_point_calc_tracer(
|
||||
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(
|
||||
|
@ -1557,7 +1572,7 @@ pub fn redeem_rewards(
|
|||
inflation_point_calc_tracer,
|
||||
) {
|
||||
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))
|
||||
} else {
|
||||
|
@ -1575,7 +1590,7 @@ pub fn calculate_points(
|
|||
vote_state: &VoteState,
|
||||
stake_history: Option<&StakeHistory>,
|
||||
) -> 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(
|
||||
stake,
|
||||
vote_state,
|
||||
|
@ -1724,6 +1739,7 @@ fn do_create_account(
|
|||
activation_epoch,
|
||||
&Config::default(),
|
||||
),
|
||||
StakeFlags::empty(),
|
||||
))
|
||||
.expect("set_state");
|
||||
|
||||
|
@ -3221,7 +3237,7 @@ mod tests {
|
|||
&stake_history
|
||||
)
|
||||
.unwrap(),
|
||||
MergeKind::Inactive(meta, stake_lamports)
|
||||
MergeKind::Inactive(meta, stake_lamports, StakeFlags::empty())
|
||||
);
|
||||
|
||||
clock.epoch = 0;
|
||||
|
@ -3258,7 +3274,7 @@ mod tests {
|
|||
..Stake::default()
|
||||
};
|
||||
stake_account
|
||||
.set_state(&StakeState::Stake(meta, stake))
|
||||
.set_state(&StakeState::Stake(meta, stake, StakeFlags::empty()))
|
||||
.unwrap();
|
||||
// activation_epoch succeeds
|
||||
assert_eq!(
|
||||
|
@ -3270,7 +3286,7 @@ mod tests {
|
|||
&stake_history
|
||||
)
|
||||
.unwrap(),
|
||||
MergeKind::ActivationEpoch(meta, stake),
|
||||
MergeKind::ActivationEpoch(meta, stake, StakeFlags::empty()),
|
||||
);
|
||||
|
||||
// all paritially activated, transient epochs fail
|
||||
|
@ -3392,7 +3408,7 @@ mod tests {
|
|||
&stake_history
|
||||
)
|
||||
.unwrap(),
|
||||
MergeKind::Inactive(meta, stake_lamports),
|
||||
MergeKind::Inactive(meta, stake_lamports, StakeFlags::empty()),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3412,8 +3428,8 @@ mod tests {
|
|||
},
|
||||
..Stake::default()
|
||||
};
|
||||
let inactive = MergeKind::Inactive(Meta::default(), lamports);
|
||||
let activation_epoch = MergeKind::ActivationEpoch(meta, stake);
|
||||
let inactive = MergeKind::Inactive(Meta::default(), lamports, StakeFlags::empty());
|
||||
let activation_epoch = MergeKind::ActivationEpoch(meta, stake, StakeFlags::empty());
|
||||
let fully_active = MergeKind::FullyActive(meta, stake);
|
||||
|
||||
assert_eq!(
|
||||
|
@ -3507,8 +3523,8 @@ mod tests {
|
|||
};
|
||||
|
||||
// activating stake merge, match credits observed
|
||||
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a);
|
||||
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b);
|
||||
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a, StakeFlags::empty());
|
||||
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b, StakeFlags::empty());
|
||||
let new_stake = activation_epoch_a
|
||||
.merge(&invoke_context, activation_epoch_b, &clock)
|
||||
.unwrap()
|
||||
|
@ -3542,8 +3558,8 @@ mod tests {
|
|||
},
|
||||
credits_observed: credits_b,
|
||||
};
|
||||
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a);
|
||||
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b);
|
||||
let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a, StakeFlags::empty());
|
||||
let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b, StakeFlags::empty());
|
||||
let new_stake = activation_epoch_a
|
||||
.merge(&invoke_context, activation_epoch_b, &clock)
|
||||
.unwrap()
|
||||
|
|
|
@ -60,7 +60,7 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> ScanResult<NonCircu
|
|||
non_circulating_accounts_set.insert(*pubkey);
|
||||
}
|
||||
}
|
||||
StakeState::Stake(meta, _stake) => {
|
||||
StakeState::Stake(meta, _stake, _stake_flags) => {
|
||||
if meta.lockup.is_in_force(&clock, None)
|
||||
|| withdraw_authority_list.contains(&meta.authorized.withdrawer)
|
||||
{
|
||||
|
|
|
@ -110,11 +110,15 @@ impl AbiExample for StakeAccount<Delegation> {
|
|||
fn example() -> Self {
|
||||
use solana_sdk::{
|
||||
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();
|
||||
account.data.resize(196, 0u8);
|
||||
account.data.resize(200, 0u8);
|
||||
account.owner = solana_stake_program::id();
|
||||
account.set_state(&stake_state).unwrap();
|
||||
Self::try_from(AccountSharedData::from(account)).unwrap()
|
||||
|
|
|
@ -362,7 +362,7 @@ fn test_stake_account_lifetime() {
|
|||
// Test that correct lamports are staked
|
||||
let account = bank.get_account(&stake_pubkey).expect("account not found");
|
||||
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,);
|
||||
} else {
|
||||
panic!("wrong account type found")
|
||||
|
@ -386,7 +386,7 @@ fn test_stake_account_lifetime() {
|
|||
// Test that lamports are still staked
|
||||
let account = bank.get_account(&stake_pubkey).expect("account not found");
|
||||
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,);
|
||||
} else {
|
||||
panic!("wrong account type found")
|
||||
|
@ -636,7 +636,7 @@ fn test_create_stake_account_from_seed() {
|
|||
// Test that correct lamports are staked
|
||||
let account = bank.get_account(&stake_pubkey).expect("account not found");
|
||||
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);
|
||||
} else {
|
||||
panic!("wrong account type found")
|
||||
|
|
|
@ -7,6 +7,7 @@ use {
|
|||
stake::{
|
||||
config::Config,
|
||||
instruction::{LockupArgs, StakeError},
|
||||
stake_flags::StakeFlags,
|
||||
},
|
||||
stake_history::{StakeHistory, StakeHistoryEntry},
|
||||
},
|
||||
|
@ -22,7 +23,7 @@ pub enum StakeState {
|
|||
#[default]
|
||||
Uninitialized,
|
||||
Initialized(Meta),
|
||||
Stake(Meta, Stake),
|
||||
Stake(Meta, Stake, StakeFlags),
|
||||
RewardsPool,
|
||||
}
|
||||
|
||||
|
@ -36,9 +37,10 @@ impl BorshDeserialize for StakeState {
|
|||
Ok(StakeState::Initialized(meta))
|
||||
}
|
||||
2 => {
|
||||
let meta = Meta::deserialize_reader(reader)?;
|
||||
let stake = Stake::deserialize_reader(reader)?;
|
||||
Ok(StakeState::Stake(meta, stake))
|
||||
let meta: Meta = BorshDeserialize::deserialize_reader(reader)?;
|
||||
let stake: Stake = BorshDeserialize::deserialize_reader(reader)?;
|
||||
let stake_flags: StakeFlags = BorshDeserialize::deserialize_reader(reader)?;
|
||||
Ok(StakeState::Stake(meta, stake, stake_flags))
|
||||
}
|
||||
3 => Ok(StakeState::RewardsPool),
|
||||
_ => Err(io::Error::new(
|
||||
|
@ -57,10 +59,11 @@ impl BorshSerialize for StakeState {
|
|||
writer.write_all(&1u32.to_le_bytes())?;
|
||||
meta.serialize(writer)
|
||||
}
|
||||
StakeState::Stake(meta, stake) => {
|
||||
StakeState::Stake(meta, stake, stake_flags) => {
|
||||
writer.write_all(&2u32.to_le_bytes())?;
|
||||
meta.serialize(writer)?;
|
||||
stake.serialize(writer)
|
||||
stake.serialize(writer)?;
|
||||
stake_flags.serialize(writer)
|
||||
}
|
||||
StakeState::RewardsPool => writer.write_all(&3u32.to_le_bytes()),
|
||||
}
|
||||
|
@ -75,21 +78,21 @@ impl StakeState {
|
|||
|
||||
pub fn stake(&self) -> Option<Stake> {
|
||||
match self {
|
||||
StakeState::Stake(_meta, stake) => Some(*stake),
|
||||
StakeState::Stake(_meta, stake, _stake_flags) => Some(*stake),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delegation(&self) -> Option<Delegation> {
|
||||
match self {
|
||||
StakeState::Stake(_meta, stake) => Some(stake.delegation),
|
||||
StakeState::Stake(_meta, stake, _stake_flags) => Some(stake.delegation),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn authorized(&self) -> Option<Authorized> {
|
||||
match self {
|
||||
StakeState::Stake(meta, _stake) => Some(meta.authorized),
|
||||
StakeState::Stake(meta, _stake, _stake_flags) => Some(meta.authorized),
|
||||
StakeState::Initialized(meta) => Some(meta.authorized),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -101,7 +104,7 @@ impl StakeState {
|
|||
|
||||
pub fn meta(&self) -> Option<Meta> {
|
||||
match self {
|
||||
StakeState::Stake(meta, _stake) => Some(*meta),
|
||||
StakeState::Stake(meta, _stake, _stake_flags) => Some(*meta),
|
||||
StakeState::Initialized(meta) => Some(*meta),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -629,6 +632,7 @@ mod test {
|
|||
},
|
||||
credits_observed: 1,
|
||||
},
|
||||
StakeFlags::empty(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -663,6 +667,7 @@ mod test {
|
|||
},
|
||||
credits_observed: 1,
|
||||
},
|
||||
StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue