@@ -222,6 +222,42 @@ fn stake_is_inactive_without_history(stake: &stake::state::Stake, epoch: Epoch)
222
222
&& stake. delegation . deactivation_epoch == epoch)
223
223
}
224
224
225
+ /// Roughly checks if a stake account is deactivating or inactive
226
+ fn check_if_stake_is_deactivating_or_inactive (
227
+ account_info : & AccountInfo ,
228
+ vote_account_address : & Pubkey ,
229
+ ) -> Result < ( ) , ProgramError > {
230
+ let ( _, stake) = get_stake_state ( account_info) ?;
231
+ if stake. delegation . deactivation_epoch == Epoch :: MAX {
232
+ msg ! (
233
+ "Existing stake {} delegated to {} is activating or active" ,
234
+ account_info. key,
235
+ vote_account_address
236
+ ) ;
237
+ Err ( StakePoolError :: WrongStakeState . into ( ) )
238
+ } else {
239
+ Ok ( ( ) )
240
+ }
241
+ }
242
+
243
+ /// Roughly checks if a stake account is activating or active
244
+ fn check_if_stake_is_activating_or_active (
245
+ account_info : & AccountInfo ,
246
+ vote_account_address : & Pubkey ,
247
+ ) -> Result < ( ) , ProgramError > {
248
+ let ( _, stake) = get_stake_state ( account_info) ?;
249
+ if stake. delegation . deactivation_epoch != Epoch :: MAX {
250
+ msg ! (
251
+ "Existing stake {} delegated to {} is deactivating or inactive" ,
252
+ account_info. key,
253
+ vote_account_address
254
+ ) ;
255
+ Err ( StakePoolError :: WrongStakeState . into ( ) )
256
+ } else {
257
+ Ok ( ( ) )
258
+ }
259
+ }
260
+
225
261
/// Check that the stake state is correct: usable by the pool and delegated to
226
262
/// the expected validator
227
263
fn check_stake_state (
@@ -1337,8 +1373,10 @@ impl Processor {
1337
1373
) ;
1338
1374
return Err ( ProgramError :: InvalidSeeds ) ;
1339
1375
}
1340
- // Let the runtime check to see if the merge is valid, so there's no
1341
- // explicit check here that the transient stake is decreasing
1376
+ check_if_stake_is_deactivating_or_inactive (
1377
+ transient_stake_account_info,
1378
+ & vote_account_address,
1379
+ ) ?;
1342
1380
}
1343
1381
1344
1382
let stake_minimum_delegation = stake:: tools:: get_minimum_delegation ( ) ?;
@@ -1586,8 +1624,10 @@ impl Processor {
1586
1624
) ;
1587
1625
return Err ( ProgramError :: InvalidSeeds ) ;
1588
1626
}
1589
- // Let the runtime check to see if the merge is valid, so there's no
1590
- // explicit check here that the transient stake is increasing
1627
+ check_if_stake_is_activating_or_active (
1628
+ transient_stake_account_info,
1629
+ vote_account_address,
1630
+ ) ?;
1591
1631
}
1592
1632
1593
1633
check_validator_stake_account (
@@ -2037,6 +2077,10 @@ impl Processor {
2037
2077
destination_transient_stake_seed,
2038
2078
& stake_pool. lockup ,
2039
2079
) ?;
2080
+ check_if_stake_is_activating_or_active (
2081
+ destination_transient_stake_account_info,
2082
+ vote_account_address,
2083
+ ) ?;
2040
2084
Self :: stake_merge (
2041
2085
stake_pool_info. key ,
2042
2086
ephemeral_stake_account_info. clone ( ) ,
0 commit comments