Limited Unbonding Chunks. (#2700)

* Limit number of unlocking chunks.

* Bump.
This commit is contained in:
Kian Peymani
2019-05-29 14:17:58 +02:00
committed by Gavin Wood
parent 91a241ad5b
commit 810d2712da
3 changed files with 49 additions and 4 deletions
+2 -2
View File
@@ -58,8 +58,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10,
spec_version: 87,
impl_version: 87,
spec_version: 88,
impl_version: 88,
apis: RUNTIME_API_VERSIONS,
};
+15 -2
View File
@@ -214,6 +214,11 @@
//! removed. Once the `BondingDuration` is over, the [`withdraw_unbonded`](./enum.Call.html#variant.withdraw_unbonded) call can be used
//! to actually withdraw the funds.
//!
//! Note that there is a limitation to the number of fund-chunks that can be scheduled to be unlocked in the future
//! via [`unbond`](enum.Call.html#variant.unbond).
//! In case this maximum (`MAX_UNLOCKING_CHUNKS`) is reached, the bonded account _must_ first wait until a successful
//! call to `withdraw_unbonded` to remove some of the chunks.
//!
//! ### Election Algorithm
//!
//! The current election algorithm is implemented based on Phragmén.
@@ -266,6 +271,8 @@ const RECENT_OFFLINE_COUNT: usize = 32;
const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4;
const MAX_NOMINATIONS: usize = 16;
const MAX_UNSTAKE_THRESHOLD: u32 = 10;
const MAX_UNLOCKING_CHUNKS: usize = 32;
const STAKING_ID: LockIdentifier = *b"staking ";
/// Indicates the initial status of the staker.
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
@@ -426,8 +433,6 @@ pub trait Trait: system::Trait + session::Trait {
type Reward: OnUnbalanced<PositiveImbalanceOf<Self>>;
}
const STAKING_ID: LockIdentifier = *b"staking ";
decl_storage! {
trait Store for Module<T: Trait> as Staking {
@@ -605,12 +610,20 @@ decl_module! {
/// Once the unlock period is done, you can call `withdraw_unbonded` to actually move
/// the funds out of management ready for transfer.
///
/// No more than a limited number of unlocking chunks (see `MAX_UNLOCKING_CHUNKS`)
/// can co-exists at the same time. In that case, [`Call::withdraw_unbonded`] need
/// to be called first to remove some of the chunks (if possible).
///
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
///
/// See also [`Call::withdraw_unbonded`].
fn unbond(origin, #[compact] value: BalanceOf<T>) {
let controller = ensure_signed(origin)?;
let mut ledger = Self::ledger(&controller).ok_or("not a controller")?;
ensure!(
ledger.unlocking.len() < MAX_UNLOCKING_CHUNKS,
"can not schedule more unlock chunks"
);
let mut value = value.min(ledger.active);
+32
View File
@@ -1237,6 +1237,38 @@ fn bond_extra_and_withdraw_unbonded_works() {
})
}
#[test]
fn too_many_unbond_calls_should_not_work() {
with_externalities(&mut ExtBuilder::default().build(), || {
// locked at era 0 until 3
for _ in 0..MAX_UNLOCKING_CHUNKS-1 {
assert_ok!(Staking::unbond(Origin::signed(10), 1));
}
System::set_block_number(1);
Session::check_rotate_session(System::block_number());
// locked ar era 1 until 4
assert_ok!(Staking::unbond(Origin::signed(10), 1));
// can't do more.
assert_noop!(Staking::unbond(Origin::signed(10), 1), "can not schedule more unlock chunks");
System::set_block_number(2);
Session::check_rotate_session(System::block_number());
System::set_block_number(3);
Session::check_rotate_session(System::block_number());
assert_noop!(Staking::unbond(Origin::signed(10), 1), "can not schedule more unlock chunks");
// free up.
assert_ok!(Staking::withdraw_unbonded(Origin::signed(10)));
// Can add again.
assert_ok!(Staking::unbond(Origin::signed(10), 1));
assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2);
})
}
#[test]
fn slot_stake_is_least_staked_validator_and_exposure_defines_maximum_punishment() {
// Test that slot_stake is determined by the least staked validator