From 41067de5e43699b51c3236d575fc234b79b772d5 Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Tue, 15 Oct 2019 12:50:31 -0700 Subject: [PATCH] multiple deactivation (#6354) --- programs/stake_api/src/stake_instruction.rs | 2 ++ programs/stake_api/src/stake_state.rs | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/programs/stake_api/src/stake_instruction.rs b/programs/stake_api/src/stake_instruction.rs index e0cab0f94..dd1b8e554 100644 --- a/programs/stake_api/src/stake_instruction.rs +++ b/programs/stake_api/src/stake_instruction.rs @@ -20,6 +20,7 @@ use solana_sdk::{ pub enum StakeError { NoCreditsToRedeem, LockupInForce, + AlreadyDeactivated, } impl DecodeError for StakeError { fn type_of() -> &'static str { @@ -31,6 +32,7 @@ impl std::fmt::Display for StakeError { match self { StakeError::NoCreditsToRedeem => write!(f, "not enough credits to redeem"), StakeError::LockupInForce => write!(f, "lockup has not yet expired"), + StakeError::AlreadyDeactivated => write!(f, "stake already deactivated"), } } } diff --git a/programs/stake_api/src/stake_state.rs b/programs/stake_api/src/stake_state.rs index 6aa596bbd..4204b073e 100644 --- a/programs/stake_api/src/stake_state.rs +++ b/programs/stake_api/src/stake_state.rs @@ -396,8 +396,13 @@ impl Stake { } } - fn deactivate(&mut self, epoch: u64) { - self.deactivation_epoch = epoch; + fn deactivate(&mut self, epoch: u64) -> Result<(), StakeError> { + if self.deactivation_epoch != std::u64::MAX { + Err(StakeError::AlreadyDeactivated) + } else { + self.deactivation_epoch = epoch; + Ok(()) + } } } @@ -512,7 +517,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> { ) -> Result<(), InstructionError> { if let StakeState::Stake(authorized, lockup, mut stake) = self.state()? { authorized.check(signers, StakeAuthorize::Staker)?; - stake.deactivate(clock.epoch); + stake.deactivate(clock.epoch)?; self.set_state(&StakeState::Stake(authorized, lockup, stake)) } else { @@ -1250,6 +1255,12 @@ mod tests { stake_keyed_account.deactivate_stake(&clock, &signers), Ok(()) ); + + // verify that deactivate() only works once + assert_eq!( + stake_keyed_account.deactivate_stake(&clock, &signers), + Err(StakeError::AlreadyDeactivated.into()) + ); } #[test]