From a7f2fff2193b0034e0b98a73f36ce4c6e78d2ae7 Mon Sep 17 00:00:00 2001 From: Brooks Prumo Date: Fri, 21 Jan 2022 19:27:53 -0600 Subject: [PATCH] Remove active features stake program v3 and v4 (#22612) Co-authored-by: Jon Cinque --- programs/stake/src/stake_instruction.rs | 26 +- programs/stake/src/stake_state.rs | 390 ++++-------------------- sdk/program/src/stake/state.rs | 29 +- sdk/src/feature_set.rs | 10 - stake-accounts/src/stake_accounts.rs | 11 +- 5 files changed, 77 insertions(+), 389 deletions(-) diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 2d96df19a..dcb209684 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -123,9 +123,6 @@ pub fn process_instruction( } } StakeInstruction::DelegateStake => { - let can_reverse_deactivation = invoke_context - .feature_set - .is_active(&feature_set::stake_program_v4::id()); let vote = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; me.delegate( @@ -143,7 +140,6 @@ pub fn process_instruction( first_instruction_account + 4, )?)?, &signers, - can_reverse_deactivation, ) } StakeInstruction::Split(lamports) => { @@ -154,9 +150,6 @@ pub fn process_instruction( StakeInstruction::Merge => { let source_stake = &keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; - let can_merge_expired_lockups = invoke_context - .feature_set - .is_active(&feature_set::stake_program_v4::id()); me.merge( invoke_context, source_stake, @@ -169,7 +162,6 @@ pub fn process_instruction( first_instruction_account + 3, )?)?, &signers, - can_merge_expired_lockups, ) } StakeInstruction::Withdraw(lamports) => { @@ -187,9 +179,6 @@ pub fn process_instruction( )?)?, keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, keyed_account_at_index(keyed_accounts, first_instruction_account + 5).ok(), - invoke_context - .feature_set - .is_active(&feature_set::stake_program_v4::id()), ) } StakeInstruction::Deactivate => me.deactivate( @@ -200,15 +189,8 @@ pub fn process_instruction( &signers, ), StakeInstruction::SetLockup(lockup) => { - let clock = if invoke_context - .feature_set - .is_active(&feature_set::stake_program_v4::id()) - { - Some(invoke_context.get_sysvar_cache().get_clock()?) - } else { - None - }; - me.set_lockup(&lockup, &signers, clock.as_deref()) + let clock = invoke_context.get_sysvar_cache().get_clock()?; + me.set_lockup(&lockup, &signers, &clock) } StakeInstruction::InitializeChecked => { if invoke_context @@ -326,8 +308,8 @@ pub fn process_instruction( epoch: lockup_checked.epoch, custodian, }; - let clock = Some(invoke_context.get_sysvar_cache().get_clock()?); - me.set_lockup(&lockup, &signers, clock.as_deref()) + let clock = invoke_context.get_sysvar_cache().get_clock()?; + me.set_lockup(&lockup, &signers, &clock) } else { Err(InstructionError::InvalidInstructionData) } diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index f8baa600e..0d163f281 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -94,7 +94,6 @@ fn redelegate( clock: &Clock, stake_history: &StakeHistory, config: &Config, - can_reverse_deactivation: bool, ) -> Result<(), StakeError> { // If stake is currently active: if stake.stake(clock.epoch, Some(stake_history)) != 0 { @@ -103,7 +102,6 @@ fn redelegate( // we rescind deactivation if stake.delegation.voter_pubkey == *voter_pubkey && clock.epoch == stake.delegation.deactivation_epoch - && can_reverse_deactivation { stake.delegation.deactivation_epoch = std::u64::MAX; return Ok(()); @@ -377,14 +375,13 @@ pub trait StakeAccount { stake_history: &StakeHistory, config: &Config, signers: &HashSet, - can_reverse_deactivation: bool, ) -> Result<(), InstructionError>; fn deactivate(&self, clock: &Clock, signers: &HashSet) -> Result<(), InstructionError>; fn set_lockup( &self, lockup: &LockupArgs, signers: &HashSet, - clock: Option<&Clock>, + clock: &Clock, ) -> Result<(), InstructionError>; fn split( &self, @@ -399,7 +396,6 @@ pub trait StakeAccount { clock: &Clock, stake_history: &StakeHistory, signers: &HashSet, - can_merge_expired_lockups: bool, ) -> Result<(), InstructionError>; fn withdraw( &self, @@ -409,7 +405,6 @@ pub trait StakeAccount { stake_history: &StakeHistory, withdraw_authority: &KeyedAccount, custodian: Option<&KeyedAccount>, - prevent_withdraw_to_zero: bool, ) -> Result<(), InstructionError>; } @@ -517,7 +512,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> { stake_history: &StakeHistory, config: &Config, signers: &HashSet, - can_reverse_deactivation: bool, ) -> Result<(), InstructionError> { if vote_account.owner()? != solana_vote_program::id() { return Err(InstructionError::IncorrectProgramId); @@ -545,7 +539,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> { clock, stake_history, config, - can_reverse_deactivation, )?; self.set_state(&StakeState::Stake(meta, stake)) } @@ -566,7 +559,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { &self, lockup: &LockupArgs, signers: &HashSet, - clock: Option<&Clock>, + clock: &Clock, ) -> Result<(), InstructionError> { match self.state()? { StakeState::Initialized(mut meta) => { @@ -705,7 +698,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> { clock: &Clock, stake_history: &StakeHistory, signers: &HashSet, - can_merge_expired_lockups: bool, ) -> Result<(), InstructionError> { // Ensure source isn't spoofed if source_account.owner()? != id() { @@ -728,12 +720,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> { let source_merge_kind = MergeKind::get_if_mergeable(invoke_context, source_account, clock, stake_history)?; - let clock = if can_merge_expired_lockups { - Some(clock) - } else { - None - }; - ic_msg!(invoke_context, "Merging stake accounts"); if let Some(merged_state) = stake_merge_kind.merge(invoke_context, source_merge_kind, clock)? @@ -761,7 +747,6 @@ impl<'a> StakeAccount for KeyedAccount<'a> { stake_history: &StakeHistory, withdraw_authority: &KeyedAccount, custodian: Option<&KeyedAccount>, - prevent_withdraw_to_zero: bool, ) -> Result<(), InstructionError> { let mut signers = HashSet::new(); let withdraw_authority_pubkey = withdraw_authority @@ -789,11 +774,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { StakeState::Initialized(meta) => { meta.authorized .check(&signers, StakeAuthorize::Withdrawer)?; - let reserve = if prevent_withdraw_to_zero { - checked_add(meta.rent_exempt_reserve, 1)? // stake accounts must have a balance > rent_exempt_reserve - } else { - meta.rent_exempt_reserve - }; + let reserve = checked_add(meta.rent_exempt_reserve, 1)?; // stake accounts must have a balance > rent_exempt_reserve (meta.lockup, reserve, false) } @@ -899,18 +880,11 @@ impl MergeKind { invoke_context: &InvokeContext, stake: &Meta, source: &Meta, - clock: Option<&Clock>, + clock: &Clock, ) -> Result<(), InstructionError> { - let can_merge_lockups = match clock { - // pre-v4 behavior. lockups must match, even when expired - None => stake.lockup == source.lockup, - // v4 behavior. lockups may mismatch so long as both have expired - Some(clock) => { - stake.lockup == source.lockup - || (!stake.lockup.is_in_force(clock, None) - && !source.lockup.is_in_force(clock, None)) - } - }; + // lockups may mismatch so long as both have expired + let can_merge_lockups = stake.lockup == source.lockup + || (!stake.lockup.is_in_force(clock, None) && !source.lockup.is_in_force(clock, None)); // `rent_exempt_reserve` has no bearing on the mergeability of accounts, // as the source account will be culled by runtime once the operation // succeeds. Considering it here would needlessly prevent merging stake @@ -970,7 +944,7 @@ impl MergeKind { self, invoke_context: &InvokeContext, source: Self, - clock: Option<&Clock>, + clock: &Clock, ) -> Result, InstructionError> { Self::metas_can_merge(invoke_context, self.meta(), source.meta(), clock)?; self.active_stake() @@ -1547,7 +1521,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Err(InstructionError::MissingRequiredSignature) ); @@ -1562,7 +1535,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ) .is_ok()); @@ -1592,7 +1564,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true ), Err(StakeError::TooSoonToRedelegate.into()) ); @@ -1609,7 +1580,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Err(StakeError::TooSoonToRedelegate.into()) ); @@ -1623,7 +1593,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ) .unwrap(); @@ -1640,7 +1609,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Err(StakeError::TooSoonToRedelegate.into()) ); @@ -1659,7 +1627,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ) .is_ok()); @@ -1677,7 +1644,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Err(solana_sdk::instruction::InstructionError::IncorrectProgramId) ); @@ -1709,7 +1675,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ) .is_err()); } @@ -2434,7 +2399,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Ok(()) ); @@ -2468,11 +2432,12 @@ mod tests { &id(), ) .expect("stake_account"); + let clock = Clock::default(); // wrong state, should fail let stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &stake_account); assert_eq!( - stake_keyed_account.set_lockup(&LockupArgs::default(), &HashSet::default(), None), + stake_keyed_account.set_lockup(&LockupArgs::default(), &HashSet::default(), &clock), Err(InstructionError::InvalidAccountData) ); @@ -2491,7 +2456,7 @@ mod tests { .unwrap(); assert_eq!( - stake_keyed_account.set_lockup(&LockupArgs::default(), &HashSet::default(), None), + stake_keyed_account.set_lockup(&LockupArgs::default(), &HashSet::default(), &clock), Err(InstructionError::MissingRequiredSignature) ); @@ -2503,7 +2468,7 @@ mod tests { custodian: Some(custodian), }, &vec![custodian].into_iter().collect(), - None + &clock ), Ok(()) ); @@ -2528,7 +2493,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &vec![stake_pubkey].into_iter().collect(), - true, ) .unwrap(); @@ -2540,7 +2504,7 @@ mod tests { custodian: Some(custodian), }, &HashSet::default(), - None + &clock ), Err(InstructionError::MissingRequiredSignature) ); @@ -2552,133 +2516,14 @@ mod tests { custodian: Some(custodian), }, &vec![custodian].into_iter().collect(), - None + &clock ), Ok(()) ); } #[test] - fn test_optional_lockup_for_stake_program_v3_and_earlier() { - let stake_pubkey = solana_sdk::pubkey::new_rand(); - let stake_lamports = 42; - let stake_account = AccountSharedData::new_ref_data_with_space( - stake_lamports, - &StakeState::Uninitialized, - std::mem::size_of::(), - &id(), - ) - .expect("stake_account"); - let stake_keyed_account = KeyedAccount::new(&stake_pubkey, false, &stake_account); - - let custodian = solana_sdk::pubkey::new_rand(); - stake_keyed_account - .initialize( - &Authorized::auto(&stake_pubkey), - &Lockup { - unix_timestamp: 1, - epoch: 1, - custodian, - }, - &Rent::free(), - ) - .unwrap(); - - assert_eq!( - stake_keyed_account.set_lockup( - &LockupArgs { - unix_timestamp: None, - epoch: None, - custodian: None, - }, - &vec![custodian].into_iter().collect(), - None - ), - Ok(()) - ); - - assert_eq!( - stake_keyed_account.set_lockup( - &LockupArgs { - unix_timestamp: Some(2), - epoch: None, - custodian: None, - }, - &vec![custodian].into_iter().collect(), - None - ), - Ok(()) - ); - - if let StakeState::Initialized(Meta { lockup, .. }) = - from(&stake_keyed_account.account.borrow()).unwrap() - { - assert_eq!(lockup.unix_timestamp, 2); - assert_eq!(lockup.epoch, 1); - assert_eq!(lockup.custodian, custodian); - } else { - panic!(); - } - - assert_eq!( - stake_keyed_account.set_lockup( - &LockupArgs { - unix_timestamp: None, - epoch: Some(3), - custodian: None, - }, - &vec![custodian].into_iter().collect(), - None - ), - Ok(()) - ); - - if let StakeState::Initialized(Meta { lockup, .. }) = - from(&stake_keyed_account.account.borrow()).unwrap() - { - assert_eq!(lockup.unix_timestamp, 2); - assert_eq!(lockup.epoch, 3); - assert_eq!(lockup.custodian, custodian); - } else { - panic!(); - } - - let new_custodian = solana_sdk::pubkey::new_rand(); - assert_eq!( - stake_keyed_account.set_lockup( - &LockupArgs { - unix_timestamp: None, - epoch: None, - custodian: Some(new_custodian), - }, - &vec![custodian].into_iter().collect(), - None - ), - Ok(()) - ); - - if let StakeState::Initialized(Meta { lockup, .. }) = - from(&stake_keyed_account.account.borrow()).unwrap() - { - assert_eq!(lockup.unix_timestamp, 2); - assert_eq!(lockup.epoch, 3); - assert_eq!(lockup.custodian, new_custodian); - } else { - panic!(); - } - - assert_eq!( - stake_keyed_account.set_lockup( - &LockupArgs::default(), - &vec![custodian].into_iter().collect(), - None - ), - Err(InstructionError::MissingRequiredSignature) - ); - } - - #[test] - fn test_optional_lockup_for_stake_program_v4() { + fn test_optional_lockup_for_stake_program() { let stake_pubkey = solana_sdk::pubkey::new_rand(); let stake_lamports = 42; let stake_account = AccountSharedData::new_ref_data_with_space( @@ -2712,7 +2557,7 @@ mod tests { custodian: None }, &vec![stake_pubkey].into_iter().collect(), - Some(&Clock::default()) + &Clock::default() ), Err(InstructionError::MissingRequiredSignature) ); @@ -2726,7 +2571,7 @@ mod tests { custodian: None }, &vec![custodian].into_iter().collect(), - Some(&Clock::default()) + &Clock::default() ), Ok(()) ); @@ -2736,11 +2581,11 @@ mod tests { stake_keyed_account.set_lockup( &LockupArgs::default(), &vec![custodian].into_iter().collect(), - Some(&Clock { + &Clock { unix_timestamp: UnixTimestamp::MAX, epoch: Epoch::MAX, ..Clock::default() - }) + } ), Err(InstructionError::MissingRequiredSignature) ); @@ -2750,11 +2595,11 @@ mod tests { stake_keyed_account.set_lockup( &LockupArgs::default(), &vec![stake_pubkey].into_iter().collect(), - Some(&Clock { + &Clock { unix_timestamp: UnixTimestamp::MAX, epoch: Epoch::MAX, ..Clock::default() - }) + } ), Ok(()) ); @@ -2778,11 +2623,11 @@ mod tests { stake_keyed_account.set_lockup( &LockupArgs::default(), &vec![stake_pubkey].into_iter().collect(), - Some(&Clock { + &Clock { unix_timestamp: UnixTimestamp::MAX, epoch: Epoch::MAX, ..Clock::default() - }) + } ), Err(InstructionError::MissingRequiredSignature) ); @@ -2816,7 +2661,6 @@ mod tests { &StakeHistory::default(), &to_keyed_account, // unsigned account as withdraw authority None, - true, ), Err(InstructionError::MissingRequiredSignature) ); @@ -2832,7 +2676,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Ok(()) ); @@ -2868,7 +2711,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -2893,7 +2735,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Ok(()) ); @@ -2911,7 +2752,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Ok(()) ); @@ -2929,7 +2769,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -2949,7 +2788,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -2964,7 +2802,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Ok(()) ); @@ -3021,7 +2858,6 @@ mod tests { &StakeHistory::default(), &authority_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds), ); @@ -3070,7 +2906,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ), Ok(()) ); @@ -3092,7 +2927,6 @@ mod tests { &stake_history, &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -3122,7 +2956,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InvalidAccountData) ); @@ -3165,7 +2998,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(StakeError::LockupInForce.into()) ); @@ -3181,7 +3013,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, Some(&custodian_keyed_account), - true, ), Ok(()) ); @@ -3203,7 +3034,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Ok(()) ); @@ -3247,7 +3077,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(StakeError::LockupInForce.into()) ); @@ -3262,7 +3091,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, Some(&custodian_keyed_account), - true, ), Ok(()) ); @@ -3292,24 +3120,24 @@ mod tests { let to_account = AccountSharedData::new_ref(1, 0, &system_program::id()); let to_keyed_account = KeyedAccount::new(&to, false, &to_account); - // Withdrawing account down to only rent-exempt reserve should succeed before feature, and - // fail after + // Withdrawing account down to minimum balance should succeed let stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &stake_account); assert_eq!( stake_keyed_account.withdraw( - stake, + stake - 1, &to_keyed_account, &clock, &StakeHistory::default(), &stake_keyed_account, None, - false, ), Ok(()) ); + + // Withdrawing account down to only rent-exempt reserve should fail stake_account .borrow_mut() - .checked_add_lamports(stake) + .checked_add_lamports(stake - 1) .unwrap(); // top up account let stake_keyed_account = KeyedAccount::new(&stake_pubkey, true, &stake_account); assert_eq!( @@ -3320,7 +3148,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -3335,7 +3162,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - false, ), Err(InstructionError::InsufficientFunds) ); @@ -3348,7 +3174,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Err(InstructionError::InsufficientFunds) ); @@ -3363,7 +3188,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, None, - true, ), Ok(()) ); @@ -3871,7 +3695,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account, // old signer None, - true, ), Err(InstructionError::MissingRequiredSignature) ); @@ -3888,7 +3711,6 @@ mod tests { &StakeHistory::default(), &stake_keyed_account2, None, - true, ), Ok(()) ); @@ -5043,7 +4865,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &HashSet::new(), - false, ), Err(InstructionError::MissingRequiredSignature) ); @@ -5055,7 +4876,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &signers, - false, ), Ok(()) ); @@ -5148,7 +4968,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &signers, - false, ), Err(InstructionError::InvalidArgument), ); @@ -5204,7 +5023,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &wrong_signers, - false, ), Err(InstructionError::MissingRequiredSignature) ); @@ -5216,7 +5034,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &signers, - false, ), Err(StakeError::MergeMismatch.into()) ); @@ -5267,7 +5084,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &signers, - false, ), Err(InstructionError::InvalidAccountData) ); @@ -5312,7 +5128,6 @@ mod tests { &Clock::default(), &StakeHistory::default(), &signers, - false, ), Err(InstructionError::IncorrectProgramId) ); @@ -5410,7 +5225,6 @@ mod tests { clock, stake_history, signers, - false, ); if result.is_ok() { assert_eq!(test_source_keyed.state(), Ok(StakeState::Uninitialized),); @@ -5684,7 +5498,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &signers, - true, ) .unwrap(); @@ -5731,7 +5544,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &other_signers, - true, ), Err(InstructionError::MissingRequiredSignature) ); @@ -5745,7 +5557,6 @@ mod tests { &StakeHistory::default(), &Config::default(), &new_signers, - true, ), Ok(()) ); @@ -5797,7 +5608,6 @@ mod tests { &stake_history, &config, &signers, - true, ) .unwrap(); @@ -5818,7 +5628,6 @@ mod tests { &stake_history, &stake_keyed_account, None, - true, ) .unwrap(); let expected_balance = rent_exempt_reserve + initial_lamports - withdraw_lamports; @@ -5832,7 +5641,6 @@ mod tests { &stake_history, &config, &signers, - true, ) .unwrap(); let stake = stake_from(&stake_account.borrow()).unwrap(); @@ -5859,7 +5667,6 @@ mod tests { &stake_history, &config, &signers, - true, ) .unwrap(); let stake = stake_from(&stake_account.borrow()).unwrap(); @@ -6041,7 +5848,7 @@ mod tests { } #[test] - fn test_metas_can_merge_pre_v4() { + fn test_metas_can_merge() { let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Identical Metas can merge @@ -6049,94 +5856,7 @@ mod tests { &invoke_context, &Meta::default(), &Meta::default(), - None, - ) - .is_ok()); - - let mismatched_rent_exempt_reserve_ok = Meta { - rent_exempt_reserve: 42, - ..Meta::default() - }; - assert_ne!( - mismatched_rent_exempt_reserve_ok.rent_exempt_reserve, - Meta::default().rent_exempt_reserve - ); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &Meta::default(), - &mismatched_rent_exempt_reserve_ok, - None, - ) - .is_ok()); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &mismatched_rent_exempt_reserve_ok, - &Meta::default(), - None, - ) - .is_ok()); - - let mismatched_authorized_fails = Meta { - authorized: Authorized { - staker: Pubkey::new_unique(), - withdrawer: Pubkey::new_unique(), - }, - ..Meta::default() - }; - assert_ne!( - mismatched_authorized_fails.authorized, - Meta::default().authorized - ); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &Meta::default(), - &mismatched_authorized_fails, - None, - ) - .is_err()); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &mismatched_authorized_fails, - &Meta::default(), - None, - ) - .is_err()); - - let mismatched_lockup_fails = Meta { - lockup: Lockup { - unix_timestamp: 424242424, - epoch: 42, - custodian: Pubkey::new_unique(), - }, - ..Meta::default() - }; - assert_ne!(mismatched_lockup_fails.lockup, Meta::default().lockup); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &Meta::default(), - &mismatched_lockup_fails, - None, - ) - .is_err()); - assert!(MergeKind::metas_can_merge( - &invoke_context, - &mismatched_lockup_fails, - &Meta::default(), - None, - ) - .is_err()); - } - - #[test] - fn test_metas_can_merge_v4() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); - let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); - // Identical Metas can merge - assert!(MergeKind::metas_can_merge( - &invoke_context, - &Meta::default(), - &Meta::default(), - Some(&Clock::default()) + &Clock::default() ) .is_ok()); @@ -6152,14 +5872,14 @@ mod tests { &invoke_context, &Meta::default(), &mismatched_rent_exempt_reserve_ok, - Some(&Clock::default()) + &Clock::default() ) .is_ok()); assert!(MergeKind::metas_can_merge( &invoke_context, &mismatched_rent_exempt_reserve_ok, &Meta::default(), - Some(&Clock::default()) + &Clock::default() ) .is_ok()); @@ -6178,14 +5898,14 @@ mod tests { &invoke_context, &Meta::default(), &mismatched_authorized_fails, - Some(&Clock::default()) + &Clock::default() ) .is_err()); assert!(MergeKind::metas_can_merge( &invoke_context, &mismatched_authorized_fails, &Meta::default(), - Some(&Clock::default()) + &Clock::default() ) .is_err()); @@ -6216,14 +5936,14 @@ mod tests { &invoke_context, &metas_with_lockup1, &metas_with_lockup2, - Some(&Clock::default()) + &Clock::default() ) .is_err()); assert!(MergeKind::metas_can_merge( &invoke_context, &metas_with_lockup2, &metas_with_lockup1, - Some(&Clock::default()) + &Clock::default() ) .is_err()); @@ -6239,14 +5959,14 @@ mod tests { &invoke_context, &metas_with_lockup1, &metas_with_lockup2, - Some(&clock) + &clock ) .is_err()); assert!(MergeKind::metas_can_merge( &invoke_context, &metas_with_lockup2, &metas_with_lockup1, - Some(&clock) + &clock ) .is_err()); @@ -6262,14 +5982,14 @@ mod tests { &invoke_context, &metas_with_lockup1, &metas_with_lockup2, - Some(&clock) + &clock ) .is_ok()); assert!(MergeKind::metas_can_merge( &invoke_context, &metas_with_lockup2, &metas_with_lockup1, - Some(&clock) + &clock ) .is_ok()); } @@ -6511,6 +6231,7 @@ mod tests { fn test_merge_kind_merge() { let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); + let clock = Clock::default(); let lamports = 424242; let meta = Meta { rent_exempt_reserve: 42, @@ -6530,37 +6251,37 @@ mod tests { assert_eq!( inactive .clone() - .merge(&invoke_context, inactive.clone(), None) + .merge(&invoke_context, inactive.clone(), &clock) .unwrap(), None ); assert_eq!( inactive .clone() - .merge(&invoke_context, activation_epoch.clone(), None) + .merge(&invoke_context, activation_epoch.clone(), &clock) .unwrap(), None ); assert!(inactive .clone() - .merge(&invoke_context, fully_active.clone(), None) + .merge(&invoke_context, fully_active.clone(), &clock) .is_err()); assert!(activation_epoch .clone() - .merge(&invoke_context, fully_active.clone(), None) + .merge(&invoke_context, fully_active.clone(), &clock) .is_err()); assert!(fully_active .clone() - .merge(&invoke_context, inactive.clone(), None) + .merge(&invoke_context, inactive.clone(), &clock) .is_err()); assert!(fully_active .clone() - .merge(&invoke_context, activation_epoch.clone(), None) + .merge(&invoke_context, activation_epoch.clone(), &clock) .is_err()); let new_state = activation_epoch .clone() - .merge(&invoke_context, inactive, None) + .merge(&invoke_context, inactive, &clock) .unwrap() .unwrap(); let delegation = new_state.delegation().unwrap(); @@ -6568,7 +6289,7 @@ mod tests { let new_state = activation_epoch .clone() - .merge(&invoke_context, activation_epoch, None) + .merge(&invoke_context, activation_epoch, &clock) .unwrap() .unwrap(); let delegation = new_state.delegation().unwrap(); @@ -6579,7 +6300,7 @@ mod tests { let new_state = fully_active .clone() - .merge(&invoke_context, fully_active, None) + .merge(&invoke_context, fully_active, &clock) .unwrap() .unwrap(); let delegation = new_state.delegation().unwrap(); @@ -6590,6 +6311,7 @@ mod tests { fn test_active_stake_merge() { let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); + let clock = Clock::default(); let delegation_a = 4_242_424_242u64; let delegation_b = 6_200_000_000u64; let credits_a = 124_521_000u64; @@ -6617,7 +6339,7 @@ mod tests { let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a); let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b); let new_stake = activation_epoch_a - .merge(&invoke_context, activation_epoch_b, None) + .merge(&invoke_context, activation_epoch_b, &clock) .unwrap() .unwrap() .stake() @@ -6632,7 +6354,7 @@ mod tests { let fully_active_a = MergeKind::FullyActive(meta, stake_a); let fully_active_b = MergeKind::FullyActive(meta, stake_b); let new_stake = fully_active_a - .merge(&invoke_context, fully_active_b, None) + .merge(&invoke_context, fully_active_b, &clock) .unwrap() .unwrap() .stake() @@ -6652,7 +6374,7 @@ mod tests { let activation_epoch_a = MergeKind::ActivationEpoch(meta, stake_a); let activation_epoch_b = MergeKind::ActivationEpoch(meta, stake_b); let new_stake = activation_epoch_a - .merge(&invoke_context, activation_epoch_b, None) + .merge(&invoke_context, activation_epoch_b, &clock) .unwrap() .unwrap() .stake() @@ -6672,7 +6394,7 @@ mod tests { let fully_active_a = MergeKind::FullyActive(meta, stake_a); let fully_active_b = MergeKind::FullyActive(meta, stake_b); let new_stake = fully_active_a - .merge(&invoke_context, fully_active_b, None) + .merge(&invoke_context, fully_active_b, &clock) .unwrap() .unwrap() .stake() @@ -6710,7 +6432,7 @@ mod tests { let fully_active_a = MergeKind::FullyActive(meta, stake_a); let fully_active_b = MergeKind::FullyActive(meta, stake_b); let new_stake = fully_active_a - .merge(&invoke_context, fully_active_b, None) + .merge(&invoke_context, fully_active_b, &clock) .unwrap() .unwrap() .stake() diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs index 004836e6b..4b73c0cf3 100644 --- a/sdk/program/src/stake/state.rs +++ b/sdk/program/src/stake/state.rs @@ -256,28 +256,17 @@ impl Meta { &mut self, lockup: &LockupArgs, signers: &HashSet, - clock: Option<&Clock>, + clock: &Clock, ) -> Result<(), InstructionError> { - match clock { - None => { - // pre-stake_program_v4 behavior: custodian can set lockups at any time - if !signers.contains(&self.lockup.custodian) { - return Err(InstructionError::MissingRequiredSignature); - } - } - Some(clock) => { - // post-stake_program_v4 behavior: - // * custodian can update the lockup while in force - // * withdraw authority can set a new lockup - // - if self.lockup.is_in_force(clock, None) { - if !signers.contains(&self.lockup.custodian) { - return Err(InstructionError::MissingRequiredSignature); - } - } else if !signers.contains(&self.authorized.withdrawer) { - return Err(InstructionError::MissingRequiredSignature); - } + // post-stake_program_v4 behavior: + // * custodian can update the lockup while in force + // * withdraw authority can set a new lockup + if self.lockup.is_in_force(clock, None) { + if !signers.contains(&self.lockup.custodian) { + return Err(InstructionError::MissingRequiredSignature); } + } else if !signers.contains(&self.authorized.withdrawer) { + return Err(InstructionError::MissingRequiredSignature); } if let Some(unix_timestamp) = lockup.unix_timestamp { self.lockup.unix_timestamp = unix_timestamp; diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index f5f7466e0..b6e5c2994 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -65,10 +65,6 @@ pub mod filter_stake_delegation_accounts { solana_sdk::declare_id!("GE7fRxmW46K6EmCD9AMZSbnaJ2e3LfqCZzdHi9hmYAgi"); } -pub mod stake_program_v3 { - solana_sdk::declare_id!("Ego6nTu7WsBcZBvVqJQKp6Yku2N3mrfG8oYCfaLZkAeK"); -} - pub mod require_custodian_for_locked_stake_authorize { solana_sdk::declare_id!("D4jsDcXaqdW8tDAWn8H4R25Cdns2YwLneujSL1zvjW6R"); } @@ -85,10 +81,6 @@ pub mod check_init_vote_data { solana_sdk::declare_id!("3ccR6QpxGYsAbWyfevEtBNGfWV4xBffxRj2tD6A9i39F"); } -pub mod stake_program_v4 { - solana_sdk::declare_id!("Dc7djyhP9aLfdq2zktpvskeAjpG56msCU1yexpxXiWZb"); -} - pub mod secp256k1_recover_syscall_enabled { solana_sdk::declare_id!("6RvdSWHh8oh72Dp7wMTS2DBkf3fRPtChfNrAo3cZZoXJ"); } @@ -320,14 +312,12 @@ lazy_static! { (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (no_overflow_rent_distribution::id(), "no overflow rent distribution"), (filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"), - (stake_program_v3::id(), "solana_stake_program v3"), (require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"), (spl_token_v2_self_transfer_fix::id(), "spl-token self-transfer fix"), (full_inflation::mainnet::certusone::enable::id(), "full inflation enabled by Certus One"), (full_inflation::mainnet::certusone::vote::id(), "community vote allowing Certus One to enable full inflation"), (warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"), (check_init_vote_data::id(), "check initialized Vote data"), - (stake_program_v4::id(), "solana_stake_program v4"), (secp256k1_recover_syscall_enabled::id(), "secp256k1_recover syscall"), (system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"), (blake3_syscall_enabled::id(), "blake3 syscall"), diff --git a/stake-accounts/src/stake_accounts.rs b/stake-accounts/src/stake_accounts.rs index e443ab37d..7df019e3f 100644 --- a/stake-accounts/src/stake_accounts.rs +++ b/stake-accounts/src/stake_accounts.rs @@ -464,13 +464,16 @@ mod tests { let custodian_keypair = Keypair::new(); let custodian_pubkey = custodian_keypair.pubkey(); + let withdrawer_keypair = Keypair::new(); + let withdrawer_pubkey = withdrawer_keypair.pubkey(); + let message = new_stake_account( &fee_payer_pubkey, &funding_pubkey, &base_pubkey, lamports, &Pubkey::default(), - &Pubkey::default(), + &withdrawer_pubkey, &custodian_pubkey, 0, ); @@ -483,16 +486,17 @@ mod tests { let lockups = get_lockups(&bank_client, &base_pubkey, 1); let messages = lockup_stake_accounts( &fee_payer_pubkey, - &custodian_pubkey, + &withdrawer_pubkey, &LockupArgs { unix_timestamp: Some(1), + custodian: Some(custodian_pubkey), ..LockupArgs::default() }, &lockups, None, ); - let signers = [&fee_payer_keypair, &custodian_keypair]; + let signers = [&fee_payer_keypair, &withdrawer_keypair]; for message in messages { bank_client .send_and_confirm_message(&signers, message) @@ -501,6 +505,7 @@ mod tests { let account = get_account_at(&bank_client, &base_pubkey, 0); let lockup = stake_state::lockup_from(&account).unwrap(); + assert_eq!(lockup.custodian, custodian_pubkey); assert_eq!(lockup.unix_timestamp, 1); assert_eq!(lockup.epoch, 0);