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(),
|
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(),
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!"),
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue