|
@@ -804,22 +804,21 @@ fn unstake() {
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
-fn immediate_slashing() {
|
|
|
+fn immediate_slashing_cannot_slash_non_existent_stake() {
|
|
|
build_test_externalities().execute_with(|| {
|
|
|
- let staked_amount = Balances::minimum_balance() + 10000;
|
|
|
- let _ = Balances::deposit_creating(&StakePool::stake_pool_account_id(), staked_amount);
|
|
|
-
|
|
|
- // NegativeImbalance doesn't impl Debug so we cannot use this macro
|
|
|
- // assert_err!(
|
|
|
- // StakePool::slash_immediate(&100, 5000, false),
|
|
|
- // StakeActionError::StakeNotFound
|
|
|
- // );
|
|
|
-
|
|
|
- // Cannot slash non-existant stake
|
|
|
let outcome = StakePool::slash_immediate(&100, 5000, false);
|
|
|
assert!(outcome.is_err());
|
|
|
let error = outcome.err().unwrap();
|
|
|
assert_eq!(error, StakeActionError::StakeNotFound);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn immediate_slashing_without_unstaking() {
|
|
|
+ build_test_externalities().execute_with(|| {
|
|
|
+ const UNSTAKE_POLICY: bool = false;
|
|
|
+ let staked_amount = Balances::minimum_balance() + 10000;
|
|
|
+ let _ = Balances::deposit_creating(&StakePool::stake_pool_account_id(), staked_amount);
|
|
|
|
|
|
let stake_id = StakePool::create_stake();
|
|
|
let created_at = System::block_number();
|
|
@@ -836,7 +835,7 @@ fn immediate_slashing() {
|
|
|
|
|
|
let slash_amount = 5000;
|
|
|
|
|
|
- let outcome = StakePool::slash_immediate(&stake_id, slash_amount, false);
|
|
|
+ let outcome = StakePool::slash_immediate(&stake_id, slash_amount, UNSTAKE_POLICY);
|
|
|
assert!(outcome.is_ok());
|
|
|
let outcome = outcome.ok().unwrap();
|
|
|
|
|
@@ -859,9 +858,57 @@ fn immediate_slashing() {
|
|
|
}
|
|
|
);
|
|
|
|
|
|
+ // slash to zero but without asking to unstake
|
|
|
// Slash and unstake by making slash go to zero
|
|
|
let slash_amount = outcome.remaining_stake;
|
|
|
- let outcome = StakePool::slash_immediate(&stake_id, outcome.remaining_stake, true)
|
|
|
+ let outcome = StakePool::slash_immediate(&stake_id, slash_amount, UNSTAKE_POLICY)
|
|
|
+ .ok()
|
|
|
+ .unwrap();
|
|
|
+ assert_eq!(outcome.caused_unstake, false);
|
|
|
+ assert_eq!(outcome.actually_slashed, slash_amount);
|
|
|
+ assert_eq!(outcome.remaining_stake, 0);
|
|
|
+ // Default handler destroys imbalance
|
|
|
+ assert_eq!(outcome.remaining_imbalance.peek(), 0);
|
|
|
+
|
|
|
+ // Should still be staked, even if staked amount = 0
|
|
|
+ assert_eq!(
|
|
|
+ <Stakes<Test>>::get(stake_id),
|
|
|
+ Stake {
|
|
|
+ created: created_at,
|
|
|
+ staking_status: StakingStatus::Staked(StakedState {
|
|
|
+ staked_amount: 0,
|
|
|
+ staked_status: StakedStatus::Normal,
|
|
|
+ next_slash_id: 0,
|
|
|
+ ongoing_slashes: BTreeMap::new()
|
|
|
+ }),
|
|
|
+ }
|
|
|
+ );
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn immediate_slashing_with_unstaking() {
|
|
|
+ build_test_externalities().execute_with(|| {
|
|
|
+ const UNSTAKE_POLICY: bool = true;
|
|
|
+ let staked_amount = Balances::minimum_balance() + 10000;
|
|
|
+ let _ = Balances::deposit_creating(&StakePool::stake_pool_account_id(), staked_amount);
|
|
|
+
|
|
|
+ let stake_id = StakePool::create_stake();
|
|
|
+ let created_at = System::block_number();
|
|
|
+ let initial_stake_state = Stake {
|
|
|
+ created: created_at,
|
|
|
+ staking_status: StakingStatus::Staked(StakedState {
|
|
|
+ staked_amount,
|
|
|
+ staked_status: StakedStatus::Normal,
|
|
|
+ next_slash_id: 0,
|
|
|
+ ongoing_slashes: BTreeMap::new(),
|
|
|
+ }),
|
|
|
+ };
|
|
|
+ <Stakes<Test>>::insert(&stake_id, initial_stake_state);
|
|
|
+
|
|
|
+ // Slash whole amount unstake by making slash go to zero
|
|
|
+ let slash_amount = staked_amount;
|
|
|
+ let outcome = StakePool::slash_immediate(&stake_id, slash_amount, UNSTAKE_POLICY)
|
|
|
.ok()
|
|
|
.unwrap();
|
|
|
assert_eq!(outcome.caused_unstake, true);
|
|
@@ -877,8 +924,21 @@ fn immediate_slashing() {
|
|
|
staking_status: StakingStatus::NotStaked
|
|
|
}
|
|
|
);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn immediate_slashing_cannot_slash_if_not_staked() {
|
|
|
+ build_test_externalities().execute_with(|| {
|
|
|
+ let stake_id = StakePool::create_stake();
|
|
|
+ let created_at = System::block_number();
|
|
|
+ let initial_stake_state = Stake {
|
|
|
+ created: created_at,
|
|
|
+ staking_status: StakingStatus::NotStaked,
|
|
|
+ };
|
|
|
+ <Stakes<Test>>::insert(&stake_id, initial_stake_state);
|
|
|
|
|
|
- let outcome = StakePool::slash_immediate(&stake_id, outcome.remaining_stake, false);
|
|
|
+ let outcome = StakePool::slash_immediate(&stake_id, 1, false);
|
|
|
let outcome_err = outcome.err().unwrap();
|
|
|
assert_eq!(
|
|
|
outcome_err,
|
|
@@ -886,3 +946,34 @@ fn immediate_slashing() {
|
|
|
);
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn immediate_slashing_cannot_slash_zero() {
|
|
|
+ build_test_externalities().execute_with(|| {
|
|
|
+ let staked_amount = Balances::minimum_balance() + 10000;
|
|
|
+ let _ = Balances::deposit_creating(&StakePool::stake_pool_account_id(), staked_amount);
|
|
|
+
|
|
|
+ let stake_id = StakePool::create_stake();
|
|
|
+ let created_at = System::block_number();
|
|
|
+ let initial_stake_state = Stake {
|
|
|
+ created: created_at,
|
|
|
+ staking_status: StakingStatus::Staked(StakedState {
|
|
|
+ staked_amount,
|
|
|
+ staked_status: StakedStatus::Normal,
|
|
|
+ next_slash_id: 0,
|
|
|
+ ongoing_slashes: BTreeMap::new(),
|
|
|
+ }),
|
|
|
+ };
|
|
|
+ <Stakes<Test>>::insert(&stake_id, initial_stake_state);
|
|
|
+
|
|
|
+ const ZERO_SLASH_AMOUNT: u64 = 0;
|
|
|
+
|
|
|
+ let outcome_err = StakePool::slash_immediate(&stake_id, ZERO_SLASH_AMOUNT, true)
|
|
|
+ .err()
|
|
|
+ .unwrap();
|
|
|
+ assert_eq!(
|
|
|
+ outcome_err,
|
|
|
+ StakeActionError::Error(ImmediateSlashingError::SlashAmountShouldBeGreaterThanZero)
|
|
|
+ );
|
|
|
+ });
|
|
|
+}
|