diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 6d596b197d..2c02a8be17 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -83,7 +83,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 184, + spec_version: 185, impl_version: 185, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index e7d7c073a1..e5c0277f57 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -993,6 +993,17 @@ decl_module! { ensure_root(origin)?; >::put(validators); } + + /// Force a current staker to become completely unstaked, immediately. + #[weight = sr_primitives::SimpleDispatchInfo::FreeOperational] + fn force_unstake(origin, stash: T::AccountId) { + ensure_root(origin)?; + + // remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // remove all staking-related information. + Self::kill_stash(&stash); + } } } diff --git a/substrate/srml/staking/src/tests.rs b/substrate/srml/staking/src/tests.rs index 2cb7981154..2b82176457 100644 --- a/substrate/srml/staking/src/tests.rs +++ b/substrate/srml/staking/src/tests.rs @@ -22,6 +22,28 @@ use sr_primitives::{assert_eq_error_rate, traits::OnInitialize}; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; use support::{assert_ok, assert_noop, assert_eq_uvec, traits::{Currency, ReservableCurrency}}; +#[test] +fn force_unstake_works() { + // Verifies initial conditions of mock + ExtBuilder::default().build().execute_with(|| { + // Account 11 is stashed and locked, and account 10 is the controller + assert_eq!(Staking::bonded(&11), Some(10)); + // Cant transfer + assert_noop!( + Balances::transfer(Origin::signed(11), 1, 10), + "account liquidity restrictions prevent withdrawal" + ); + // Force unstake requires root. + assert_noop!(Staking::force_unstake(Origin::signed(11), 11), "RequireRootOrigin"); + // We now force them to unstake + assert_ok!(Staking::force_unstake(Origin::ROOT, 11)); + // No longer bonded. + assert_eq!(Staking::bonded(&11), None); + // Transfer works. + assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); + }); +} + #[test] fn basic_setup_works() { // Verifies initial conditions of mock