Skip to content

Commit

Permalink
stake: Remove stake_allow_zero_undelegated_amount usage
Browse files Browse the repository at this point in the history
  • Loading branch information
joncinque committed Jun 20, 2023
1 parent ad96860 commit 31cb761
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 73 deletions.
43 changes: 6 additions & 37 deletions programs/stake/src/stake_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,7 @@ declare_process_instruction!(
let mut me = get_stake_account()?;
let rent =
get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
initialize(
&mut me,
&authorized,
&lockup,
&rent,
&invoke_context.feature_set,
)
initialize(&mut me, &authorized, &lockup, &rent)
}
Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => {
let mut me = get_stake_account()?;
Expand Down Expand Up @@ -261,7 +255,6 @@ declare_process_instruction!(
} else {
None
},
&invoke_context.feature_set,
)
}
Ok(StakeInstruction::Deactivate) => {
Expand Down Expand Up @@ -302,13 +295,7 @@ declare_process_instruction!(
instruction_context,
1,
)?;
initialize(
&mut me,
&authorized,
&Lockup::default(),
&rent,
&invoke_context.feature_set,
)
initialize(&mut me, &authorized, &Lockup::default(), &rent)
} else {
Err(InstructionError::InvalidInstructionData)
}
Expand Down Expand Up @@ -525,16 +512,6 @@ mod tests {
feature_set
}

/// The "old old" behavior is both before the stake minimum delegation was raised *and* before
/// undelegated stake accounts could have zero lamports beyond rent
fn feature_set_old_old_behavior() -> Arc<FeatureSet> {
let mut feature_set = feature_set_old_behavior();
Arc::get_mut(&mut feature_set)
.unwrap()
.deactivate(&feature_set::stake_allow_zero_undelegated_amount::id());
feature_set
}

fn create_default_account() -> AccountSharedData {
AccountSharedData::new(0, 0, &Pubkey::new_unique())
}
Expand Down Expand Up @@ -4470,17 +4447,9 @@ mod tests {
/// 3. Deactives the delegation
/// 4. Withdraws from the account such that the ending balance is *below* rent + minimum delegation
/// 5. Re-delegates, now with less than the minimum delegation, but it still succeeds
//
// The "old old" behavior relies on `validate_delegated_amount()` *not* checking if the
// stake amount meets the minimum delegation. Once the
// `stake_allow_zero_undelegated_amount` feature is activated, `the expected_result`
// parameter can be removed and consolidated.
#[test_case(feature_set_old_old_behavior(), Ok(()); "old_old_behavior")]
#[test_case(feature_set_new_behavior(), Err(StakeError::InsufficientDelegation.into()); "new_behavior")]
fn test_behavior_withdrawal_then_redelegate_with_less_than_minimum_stake_delegation(
feature_set: Arc<FeatureSet>,
expected_result: Result<(), InstructionError>,
) {
#[test]
fn test_behavior_withdrawal_then_redelegate_with_less_than_minimum_stake_delegation() {
let feature_set = feature_set_new_behavior();
let minimum_delegation = crate::get_minimum_delegation(&feature_set);
let rent = Rent::default();
let rent_exempt_reserve = rent.minimum_balance(StakeState::size_of());
Expand Down Expand Up @@ -4641,7 +4610,7 @@ mod tests {
&serialize(&StakeInstruction::DelegateStake).unwrap(),
transaction_accounts,
instruction_accounts,
expected_result,
Err(StakeError::InsufficientDelegation.into()),
);
}

Expand Down
42 changes: 6 additions & 36 deletions programs/stake/src/stake_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use {
account_utils::StateMut,
clock::{Clock, Epoch},
feature_set::{
self, clean_up_delegation_errors, stake_allow_zero_undelegated_amount,
stake_merge_with_unmatched_credits_observed, stake_split_uses_rent_sysvar, FeatureSet,
self, clean_up_delegation_errors, stake_merge_with_unmatched_credits_observed,
stake_split_uses_rent_sysvar, FeatureSet,
},
instruction::{checked_add, InstructionError},
pubkey::Pubkey,
Expand Down Expand Up @@ -464,22 +464,13 @@ pub fn initialize(
authorized: &Authorized,
lockup: &Lockup,
rent: &Rent,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
if stake_account.get_data().len() != StakeState::size_of() {
return Err(InstructionError::InvalidAccountData);
}
if let StakeState::Uninitialized = stake_account.get_state()? {
let rent_exempt_reserve = rent.minimum_balance(stake_account.get_data().len());
// when removing this feature, remove `minimum_balance` and just use `rent_exempt_reserve`
let minimum_balance = if feature_set.is_active(&stake_allow_zero_undelegated_amount::id()) {
rent_exempt_reserve
} else {
let minimum_delegation = crate::get_minimum_delegation(feature_set);
rent_exempt_reserve + minimum_delegation
};

if stake_account.get_lamports() >= minimum_balance {
if stake_account.get_lamports() >= rent_exempt_reserve {
stake_account.set_state(&StakeState::Initialized(Meta {
rent_exempt_reserve,
authorized: *authorized,
Expand Down Expand Up @@ -774,14 +765,6 @@ pub fn split(
}
StakeState::Initialized(meta) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
let additional_required_lamports = if invoke_context
.feature_set
.is_active(&stake_allow_zero_undelegated_amount::id())
{
0
} else {
crate::get_minimum_delegation(&invoke_context.feature_set)
};
let validated_split_info = validate_split_amount(
invoke_context,
transaction_context,
Expand All @@ -791,7 +774,7 @@ pub fn split(
lamports,
&meta,
None,
additional_required_lamports,
0, // additional_required_lamports
)?;
let mut split_meta = meta;
split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
Expand Down Expand Up @@ -1026,7 +1009,6 @@ pub fn withdraw(
stake_history: &StakeHistory,
withdraw_authority_index: IndexOfAccount,
custodian_index: Option<IndexOfAccount>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let withdraw_authority_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context
Expand Down Expand Up @@ -1061,16 +1043,7 @@ pub fn withdraw(
meta.authorized
.check(&signers, StakeAuthorize::Withdrawer)?;
// stake accounts must have a balance >= rent_exempt_reserve
let reserve = if feature_set.is_active(&stake_allow_zero_undelegated_amount::id()) {
meta.rent_exempt_reserve
} else {
checked_add(
meta.rent_exempt_reserve,
crate::get_minimum_delegation(feature_set),
)?
};

(meta.lockup, reserve, false)
(meta.lockup, meta.rent_exempt_reserve, false)
}
StakeState::Uninitialized => {
if !signers.contains(stake_account.get_key()) {
Expand Down Expand Up @@ -1200,10 +1173,7 @@ fn validate_delegated_amount(

// Stake accounts may be initialized with a stake amount below the minimum delegation so check
// that the minimum is met before delegation.
if (feature_set.is_active(&stake_allow_zero_undelegated_amount::id())
|| feature_set.is_active(&feature_set::stake_raise_minimum_delegation_to_1_sol::id()))
&& stake_amount < crate::get_minimum_delegation(feature_set)
{
if stake_amount < crate::get_minimum_delegation(feature_set) {
return Err(StakeError::InsufficientDelegation.into());
}
Ok(ValidatedDelegatedInfo { stake_amount })
Expand Down

0 comments on commit 31cb761

Please sign in to comment.