Allow nomination pools to chill + fix dismantle scenario (#11426)

* make pool roles optional

* undo lock file changes?

* add migration

* add the ability for pools to chill themselves

* boilerplate of tests

* somewhat stable, but I think I found another bug as well

* Fix it all

* Add more more sophisticated test + capture one more bug.

* Update frame/staking/src/lib.rs

* reduce the diff a little bit

* add some test for the slashing bug

* cleanup

* fix lock file?

* Fix

* fmt

* Update frame/nomination-pools/src/lib.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update frame/nomination-pools/src/lib.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update frame/nomination-pools/src/lib.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update frame/nomination-pools/src/mock.rs

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix build

* fix some fishy tests..

* add one last integrity check for MinCreateBond

* remove bad assertion -- needs to be dealt with later

* nits

* fix tests and add benchmarks for chill

* remove stuff

* fix benchmarks

* cargo run --quiet --profile=production  --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark pallet --chain=dev --steps=50 --repeat=20 --pallet=pallet_nomination_pools --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/nomination-pools/src/weights.rs --template=./.maintain/frame-weight-template.hbs

* remove defensive

Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Parity Bot <admin@parity.io>
This commit is contained in:
Kian Paimani
2022-06-13 22:07:36 +01:00
committed by GitHub
parent 19684de7d8
commit ad1d171601
18 changed files with 1434 additions and 635 deletions
+47 -19
View File
@@ -2,7 +2,6 @@ use super::*;
use crate::{self as pools};
use frame_support::{assert_ok, parameter_types, PalletId};
use frame_system::RawOrigin;
use std::collections::HashMap;
pub type AccountId = u128;
pub type Balance = u128;
@@ -20,17 +19,19 @@ pub fn default_reward_account() -> AccountId {
parameter_types! {
pub static CurrentEra: EraIndex = 0;
pub static BondingDuration: EraIndex = 3;
static BondedBalanceMap: HashMap<AccountId, Balance> = Default::default();
static UnbondingBalanceMap: HashMap<AccountId, Balance> = Default::default();
pub storage BondedBalanceMap: BTreeMap<AccountId, Balance> = Default::default();
pub storage UnbondingBalanceMap: BTreeMap<AccountId, Balance> = Default::default();
#[derive(Clone, PartialEq)]
pub static MaxUnbonding: u32 = 8;
pub static Nominations: Vec<AccountId> = vec![];
pub storage Nominations: Option<Vec<AccountId>> = None;
}
pub struct StakingMock;
impl StakingMock {
pub(crate) fn set_bonded_balance(who: AccountId, bonded: Balance) {
BONDED_BALANCE_MAP.with(|m| m.borrow_mut().insert(who, bonded));
let mut x = BondedBalanceMap::get();
x.insert(who, bonded);
BondedBalanceMap::set(&x)
}
}
@@ -66,22 +67,33 @@ impl sp_staking::StakingInterface for StakingMock {
}
fn bond_extra(who: Self::AccountId, extra: Self::Balance) -> DispatchResult {
BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() += extra);
let mut x = BondedBalanceMap::get();
x.get_mut(&who).map(|v| *v += extra);
BondedBalanceMap::set(&x);
Ok(())
}
fn unbond(who: Self::AccountId, amount: Self::Balance) -> DispatchResult {
BONDED_BALANCE_MAP.with(|m| *m.borrow_mut().get_mut(&who).unwrap() -= amount);
UNBONDING_BALANCE_MAP
.with(|m| *m.borrow_mut().entry(who).or_insert(Self::Balance::zero()) += amount);
let mut x = BondedBalanceMap::get();
*x.get_mut(&who).unwrap() = x.get_mut(&who).unwrap().saturating_sub(amount);
BondedBalanceMap::set(&x);
let mut y = UnbondingBalanceMap::get();
*y.entry(who).or_insert(Self::Balance::zero()) += amount;
UnbondingBalanceMap::set(&y);
Ok(())
}
fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result<u64, DispatchError> {
// Simulates removing unlocking chunks and only having the bonded balance locked
let _maybe_new_free = UNBONDING_BALANCE_MAP.with(|m| m.borrow_mut().remove(&who));
fn chill(_: Self::AccountId) -> sp_runtime::DispatchResult {
Ok(())
}
Ok(100)
fn withdraw_unbonded(who: Self::AccountId, _: u32) -> Result<bool, DispatchError> {
// Simulates removing unlocking chunks and only having the bonded balance locked
let mut x = UnbondingBalanceMap::get();
x.remove(&who);
UnbondingBalanceMap::set(&x);
Ok(UnbondingBalanceMap::get().is_empty() && BondedBalanceMap::get().is_empty())
}
fn bond(
@@ -95,9 +107,13 @@ impl sp_staking::StakingInterface for StakingMock {
}
fn nominate(_: Self::AccountId, nominations: Vec<Self::AccountId>) -> DispatchResult {
Nominations::set(nominations);
Nominations::set(&Some(nominations));
Ok(())
}
fn nominations(_: Self::AccountId) -> Option<Vec<Self::AccountId>> {
Nominations::get()
}
}
impl frame_system::Config for Runtime {
@@ -162,7 +178,6 @@ parameter_types! {
pub static MaxMetadataLen: u32 = 2;
pub static CheckLevel: u8 = 255;
pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls");
pub const MinPointsToBalance: u32 = 10;
}
impl pools::Config for Runtime {
type Event = Event;
@@ -175,7 +190,7 @@ impl pools::Config for Runtime {
type PalletId = PoolsPalletId;
type MaxMetadataLen = MaxMetadataLen;
type MaxUnbonding = MaxUnbonding;
type MinPointsToBalance = MinPointsToBalance;
type MinPointsToBalance = frame_support::traits::ConstU32<10>;
}
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
@@ -265,7 +280,8 @@ pub(crate) fn unsafe_set_state(pool_id: PoolId, state: PoolState) -> Result<(),
}
parameter_types! {
static ObservedEvents: usize = 0;
static PoolsEvents: usize = 0;
static BalancesEvents: usize = 0;
}
/// All events of this pallet.
@@ -275,8 +291,20 @@ pub(crate) fn pool_events_since_last_call() -> Vec<super::Event<Runtime>> {
.map(|r| r.event)
.filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None })
.collect::<Vec<_>>();
let already_seen = ObservedEvents::get();
ObservedEvents::set(events.len());
let already_seen = PoolsEvents::get();
PoolsEvents::set(events.len());
events.into_iter().skip(already_seen).collect()
}
/// All events of the `Balances` pallet.
pub(crate) fn balances_events_since_last_call() -> Vec<pallet_balances::Event<Runtime>> {
let events = System::events()
.into_iter()
.map(|r| r.event)
.filter_map(|e| if let Event::Balances(inner) = e { Some(inner) } else { None })
.collect::<Vec<_>>();
let already_seen = BalancesEvents::get();
BalancesEvents::set(events.len());
events.into_iter().skip(already_seen).collect()
}