Browse Source

staking module: make immediate unstaking after immediate slashing optional

update versions:
  staking module major version update because of breaking change
  only impl version number bumped for runtime since consensus rules haven't been affected
Mokhtar Naamani 5 years ago
parent
commit
8e9cf2c809
3 changed files with 19 additions and 21 deletions
  1. 1 1
      runtime-modules/stake/Cargo.toml
  2. 17 19
      runtime-modules/stake/src/lib.rs
  3. 1 1
      runtime/Cargo.toml

+ 1 - 1
runtime-modules/stake/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = 'substrate-stake-module'
-version = '1.0.1'
+version = '2.0.0'
 authors = ['Joystream contributors']
 edition = '2018'
 

+ 17 - 19
runtime-modules/stake/src/lib.rs

@@ -73,6 +73,8 @@ pub trait StakingEventsHandler<T: Trait> {
     /// NB: actually_slashed can be less than amount of the slash itself if the
     /// claim amount on the stake cannot cover it fully.
     /// The SlashId is optional, as slashing may not be associated with a slashing that was initiated, but was an immediate slashing.
+    /// For Immediate slashes, the stake may have transitioned to NotStaked so handler should not assume the state
+    /// is still in staked status.
     fn slashed(
         id: &T::StakeId,
         slash_id: Option<T::SlashId>,
@@ -409,7 +411,7 @@ where
         &mut self,
         slash_amount: Balance,
         minimum_balance: Balance,
-    ) -> Result<Balance, ImmediateSlashingError> {
+    ) -> Result<(Balance, Balance), ImmediateSlashingError> {
         ensure!(
             slash_amount > Zero::zero(),
             ImmediateSlashingError::SlashAmountShouldBeGreaterThanZero
@@ -421,7 +423,9 @@ where
 
                 let actually_slashed = staked_state.apply_slash(slash_amount, minimum_balance);
 
-                Ok(actually_slashed)
+                let remaining_stake = staked_state.staked_amount;
+
+                Ok((actually_slashed, remaining_stake))
             }
             // can't slash if not staked
             _ => Err(ImmediateSlashingError::NotStaked),
@@ -965,13 +969,13 @@ impl<T: Trait> Module<T> {
         Ok(staked_amount)
     }
 
-    /// Slashes a stake with immediate effect, returns actual slashed amount as an imbalance.
-    /// If attempt to slash more than staked amount, actual slashed amount may be less than requested amount to slash.
-    /// Slashing adheres to system minimum balance, so if slashing results in amount at staked going below the
-    /// minimum balance, the entire stake will be slashed, and the state of the stake will change to Unstaked.
+    /// Slashes a stake with immediate effect, returns the outcome of the slashing.
+    /// Can optionally specify if slashing can result in immediate unstaking if staked amount
+    /// after slashing goes to zero.
     pub fn slash_immediate(
         stake_id: &T::StakeId,
         slash_amount: BalanceOf<T>,
+        unstake_on_zero_staked: bool,
     ) -> Result<
         SlashImmediateOutcome<BalanceOf<T>, NegativeImbalance<T>>,
         StakeActionError<ImmediateSlashingError>,
@@ -984,21 +988,11 @@ impl<T: Trait> Module<T> {
             StakeActionError::Error(ImmediateSlashingError::NotStaked)
         )?;
 
-        let actually_slashed =
+        let (actually_slashed, remaining_stake) =
             stake.slash_immediate(slash_amount, T::Currency::minimum_balance())?;
 
-        // Remove the slashed amount from the pool
-        let slashed_imbalance = Self::withdraw_funds_from_stake_pool(actually_slashed);
+        let caused_unstake = unstake_on_zero_staked && remaining_stake == BalanceOf::<T>::zero();
 
-        // What remains at stake?
-        let remaining_stake = ensure_staked_amount!(
-            stake,
-            StakeActionError::Error(ImmediateSlashingError::NotStaked)
-        )?;
-
-        let caused_unstake = remaining_stake == BalanceOf::<T>::zero();
-
-        // Set state to NotStaked if immediate slashing removed all the staked amount
         if caused_unstake {
             stake.staking_status = StakingStatus::NotStaked;
         }
@@ -1006,6 +1000,9 @@ impl<T: Trait> Module<T> {
         // Update state before calling handlers!
         <Stakes<T>>::insert(stake_id, stake);
 
+        // Remove the slashed amount from the pool
+        let slashed_imbalance = Self::withdraw_funds_from_stake_pool(actually_slashed);
+
         // Notify slashing event handler before unstaked handler.
         let remaining_imbalance_after_slash_handler = T::StakingEventsHandler::slashed(
             stake_id,
@@ -1016,7 +1013,8 @@ impl<T: Trait> Module<T> {
         );
 
         let remaining_imbalance = if caused_unstake {
-            // Notify unstaked handler with any remaining unused imbalance from the slashing event handler
+            // Notify unstaked handler with any remaining unused imbalance
+            // from the slashing event handler
             T::StakingEventsHandler::unstaked(
                 &stake_id,
                 staked_amount_before_slash,

+ 1 - 1
runtime/Cargo.toml

@@ -5,7 +5,7 @@ edition = '2018'
 name = 'joystream-node-runtime'
 # Follow convention: https://github.com/Joystream/substrate-runtime-joystream/issues/1
 # {Authoring}.{Spec}.{Impl} of the RuntimeVersion
-version = '6.8.0'
+version = '6.8.1'
 
 [features]
 default = ['std']