mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-06 06:48:01 +00:00
safe multi-era slashing for NPoS (#3846)
* define slashing spans * tests and pruning for slashing-spans record * validators get slashed before nominators * apply slash to nominators as well * chill and end slashing spans * actually perform slashes * integration (tests failing) * prune metadata * fix compilation * some tests for slashing and metadata garbage collection * correctly pass session index to slash handler * test span-max property for nominators and validators * test that slashes are summed correctly * reward value computation * implement rewarding * add comment about rewards * do not adjust slash fraction in offences module * fix offences tests * remove unused new_offenders field * update runtime version * fix up some docs * fix some CI failures * remove no-std incompatible vec! invocation * try to fix span-max rounding error * Update srml/staking/src/slashing.rs Fix type: winow -> window Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * slashes from prior spans don't kick validator again * more information for nominators, suppression * ensure ledger is consistent with itself post-slash * implement slash out of unlocking funds also * slashing: create records to be applied after-the-fact * queue slashes for a few eras later * method for canceling deferred slashes * attempt to fix test in CI * storage migration for `Nominators` * update node-runtime to use SlashDeferDuration * adjust migration entry-points somewhat * fix migration compilation * add manual Vec import to migration * enable migrations feature in node-runtime * bump runtime version * update to latest master crate renames * update to use ensure-origin * Apply suggestions from code review use `ensure!` Co-Authored-By: Gavin Wood <gavin@parity.io> * fix multi-slash removal * initialize storage version to current in genesis * add test for version initialization
This commit is contained in:
committed by
Gavin Wood
parent
de5686509c
commit
4598e13015
@@ -21,10 +21,10 @@ use sr_primitives::{Perbill, KeyTypeId};
|
||||
use sr_primitives::curve::PiecewiseLinear;
|
||||
use sr_primitives::traits::{IdentityLookup, Convert, OpaqueKeys, OnInitialize, SaturatedConversion};
|
||||
use sr_primitives::testing::{Header, UintAuthorityId};
|
||||
use sr_staking_primitives::SessionIndex;
|
||||
use sr_staking_primitives::{SessionIndex, offence::{OffenceDetails, OnOffenceHandler}};
|
||||
use primitives::{H256, crypto::key_types};
|
||||
use runtime_io;
|
||||
use support::{assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap};
|
||||
use support::{assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap, StorageValue};
|
||||
use support::traits::{Currency, Get, FindAuthor};
|
||||
use crate::{
|
||||
EraIndex, GenesisConfig, Module, Trait, StakerStatus, ValidatorPrefs, RewardDestination,
|
||||
@@ -48,6 +48,7 @@ impl Convert<u128, u64> for CurrencyToVoteHandler {
|
||||
thread_local! {
|
||||
static SESSION: RefCell<(Vec<AccountId>, HashSet<AccountId>)> = RefCell::new(Default::default());
|
||||
static EXISTENTIAL_DEPOSIT: RefCell<u64> = RefCell::new(0);
|
||||
static SLASH_DEFER_DURATION: RefCell<EraIndex> = RefCell::new(0);
|
||||
}
|
||||
|
||||
pub struct TestSessionHandler;
|
||||
@@ -87,6 +88,13 @@ impl Get<u64> for ExistentialDeposit {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SlashDeferDuration;
|
||||
impl Get<EraIndex> for SlashDeferDuration {
|
||||
fn get() -> EraIndex {
|
||||
SLASH_DEFER_DURATION.with(|v| *v.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl_outer_origin!{
|
||||
pub enum Origin for Test {}
|
||||
}
|
||||
@@ -202,6 +210,8 @@ impl Trait for Test {
|
||||
type Slash = ();
|
||||
type Reward = ();
|
||||
type SessionsPerEra = SessionsPerEra;
|
||||
type SlashDeferDuration = SlashDeferDuration;
|
||||
type SlashCancelOrigin = system::EnsureRoot<Self::AccountId>;
|
||||
type BondingDuration = BondingDuration;
|
||||
type SessionInterface = Self;
|
||||
type RewardCurve = RewardCurve;
|
||||
@@ -213,6 +223,7 @@ pub struct ExtBuilder {
|
||||
nominate: bool,
|
||||
validator_count: u32,
|
||||
minimum_validator_count: u32,
|
||||
slash_defer_duration: EraIndex,
|
||||
fair: bool,
|
||||
num_validators: Option<u32>,
|
||||
invulnerables: Vec<u64>,
|
||||
@@ -226,6 +237,7 @@ impl Default for ExtBuilder {
|
||||
nominate: true,
|
||||
validator_count: 2,
|
||||
minimum_validator_count: 0,
|
||||
slash_defer_duration: 0,
|
||||
fair: true,
|
||||
num_validators: None,
|
||||
invulnerables: vec![],
|
||||
@@ -254,6 +266,10 @@ impl ExtBuilder {
|
||||
self.minimum_validator_count = count;
|
||||
self
|
||||
}
|
||||
pub fn slash_defer_duration(mut self, eras: EraIndex) -> Self {
|
||||
self.slash_defer_duration = eras;
|
||||
self
|
||||
}
|
||||
pub fn fair(mut self, is_fair: bool) -> Self {
|
||||
self.fair = is_fair;
|
||||
self
|
||||
@@ -268,6 +284,7 @@ impl ExtBuilder {
|
||||
}
|
||||
pub fn set_associated_consts(&self) {
|
||||
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
|
||||
SLASH_DEFER_DURATION.with(|v| *v.borrow_mut() = self.slash_defer_duration);
|
||||
}
|
||||
pub fn build(self) -> runtime_io::TestExternalities {
|
||||
self.set_associated_consts();
|
||||
@@ -393,6 +410,14 @@ pub fn assert_is_stash(acc: u64) {
|
||||
assert!(Staking::bonded(&acc).is_some(), "Not a stash.");
|
||||
}
|
||||
|
||||
pub fn assert_ledger_consistent(stash: u64) {
|
||||
assert_is_stash(stash);
|
||||
let ledger = Staking::ledger(stash - 1).unwrap();
|
||||
|
||||
let real_total: Balance = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value);
|
||||
assert_eq!(real_total, ledger.total);
|
||||
}
|
||||
|
||||
pub fn bond_validator(acc: u64, val: u64) {
|
||||
// a = controller
|
||||
// a + 1 = stash
|
||||
@@ -451,3 +476,33 @@ pub fn reward_all_elected() {
|
||||
pub fn validator_controllers() -> Vec<AccountId> {
|
||||
Session::validators().into_iter().map(|s| Staking::bonded(&s).expect("no controller for validator")).collect()
|
||||
}
|
||||
|
||||
pub fn on_offence_in_era(
|
||||
offenders: &[OffenceDetails<AccountId, session::historical::IdentificationTuple<Test>>],
|
||||
slash_fraction: &[Perbill],
|
||||
era: EraIndex,
|
||||
) {
|
||||
let bonded_eras = crate::BondedEras::get();
|
||||
for &(bonded_era, start_session) in bonded_eras.iter() {
|
||||
if bonded_era == era {
|
||||
Staking::on_offence(offenders, slash_fraction, start_session);
|
||||
return
|
||||
} else if bonded_era > era {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if Staking::current_era() == era {
|
||||
Staking::on_offence(offenders, slash_fraction, Staking::current_era_start_session_index());
|
||||
} else {
|
||||
panic!("cannot slash in era {}", era);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_offence_now(
|
||||
offenders: &[OffenceDetails<AccountId, session::historical::IdentificationTuple<Test>>],
|
||||
slash_fraction: &[Perbill],
|
||||
) {
|
||||
let now = Staking::current_era();
|
||||
on_offence_in_era(offenders, slash_fraction, now)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user