@@ -221,6 +221,42 @@ fn stake_is_inactive_without_history(stake: &stake::state::Stake, epoch: Epoch)
221221 && stake. delegation . deactivation_epoch == epoch)
222222}
223223
224+ /// Roughly checks if a stake account is deactivating or inactive
225+ fn check_if_stake_is_deactivating_or_inactive (
226+ account_info : & AccountInfo ,
227+ vote_account_address : & Pubkey ,
228+ ) -> Result < ( ) , ProgramError > {
229+ let ( _, stake) = get_stake_state ( account_info) ?;
230+ if stake. delegation . deactivation_epoch == Epoch :: MAX {
231+ msg ! (
232+ "Existing stake {} delegated to {} is activating or active" ,
233+ account_info. key,
234+ vote_account_address
235+ ) ;
236+ Err ( StakePoolError :: WrongStakeState . into ( ) )
237+ } else {
238+ Ok ( ( ) )
239+ }
240+ }
241+
242+ /// Roughly checks if a stake account is activating or active
243+ fn check_if_stake_is_activating_or_active (
244+ account_info : & AccountInfo ,
245+ vote_account_address : & Pubkey ,
246+ ) -> Result < ( ) , ProgramError > {
247+ let ( _, stake) = get_stake_state ( account_info) ?;
248+ if stake. delegation . deactivation_epoch != Epoch :: MAX {
249+ msg ! (
250+ "Existing stake {} delegated to {} is deactivating or inactive" ,
251+ account_info. key,
252+ vote_account_address
253+ ) ;
254+ Err ( StakePoolError :: WrongStakeState . into ( ) )
255+ } else {
256+ Ok ( ( ) )
257+ }
258+ }
259+
224260/// Check that the stake state is correct: usable by the pool and delegated to
225261/// the expected validator
226262fn check_stake_state (
@@ -1336,8 +1372,10 @@ impl Processor {
13361372 ) ;
13371373 return Err ( ProgramError :: InvalidSeeds ) ;
13381374 }
1339- // Let the runtime check to see if the merge is valid, so there's no
1340- // explicit check here that the transient stake is decreasing
1375+ check_if_stake_is_deactivating_or_inactive (
1376+ transient_stake_account_info,
1377+ & vote_account_address,
1378+ ) ?;
13411379 }
13421380
13431381 let stake_minimum_delegation = stake:: tools:: get_minimum_delegation ( ) ?;
@@ -1585,8 +1623,10 @@ impl Processor {
15851623 ) ;
15861624 return Err ( ProgramError :: InvalidSeeds ) ;
15871625 }
1588- // Let the runtime check to see if the merge is valid, so there's no
1589- // explicit check here that the transient stake is increasing
1626+ check_if_stake_is_activating_or_active (
1627+ transient_stake_account_info,
1628+ vote_account_address,
1629+ ) ?;
15901630 }
15911631
15921632 check_validator_stake_account (
@@ -2036,6 +2076,10 @@ impl Processor {
20362076 destination_transient_stake_seed,
20372077 & stake_pool. lockup ,
20382078 ) ?;
2079+ check_if_stake_is_activating_or_active (
2080+ destination_transient_stake_account_info,
2081+ vote_account_address,
2082+ ) ?;
20392083 Self :: stake_merge (
20402084 stake_pool_info. key ,
20412085 ephemeral_stake_account_info. clone ( ) ,
0 commit comments