mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 22:51:13 +00:00
Allow validators to block and kick their nominator set. (#7930)
* Allow validators to block and kick their nominator set. * migration * Test * Better migration * Fixes * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Update frame/staking/src/lib.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Parity Benchmarking Bot <admin@parity.io> Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -454,12 +454,17 @@ pub struct ValidatorPrefs {
|
||||
/// nominators.
|
||||
#[codec(compact)]
|
||||
pub commission: Perbill,
|
||||
/// Whether or not this validator is accepting more nominations. If `true`, then no nominator
|
||||
/// who is not already nominating this validator may nominate them. By default, validators
|
||||
/// are accepting nominations.
|
||||
pub blocked: bool,
|
||||
}
|
||||
|
||||
impl Default for ValidatorPrefs {
|
||||
fn default() -> Self {
|
||||
ValidatorPrefs {
|
||||
commission: Default::default(),
|
||||
blocked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -896,11 +901,12 @@ enum Releases {
|
||||
V2_0_0,
|
||||
V3_0_0,
|
||||
V4_0_0,
|
||||
V5_0_0,
|
||||
}
|
||||
|
||||
impl Default for Releases {
|
||||
fn default() -> Self {
|
||||
Releases::V4_0_0
|
||||
Releases::V5_0_0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1087,8 +1093,8 @@ decl_storage! {
|
||||
/// True if network has been upgraded to this version.
|
||||
/// Storage version of the pallet.
|
||||
///
|
||||
/// This is set to v3.0.0 for new networks.
|
||||
StorageVersion build(|_: &GenesisConfig<T>| Releases::V4_0_0): Releases;
|
||||
/// This is set to v5.0.0 for new networks.
|
||||
StorageVersion build(|_: &GenesisConfig<T>| Releases::V5_0_0): Releases;
|
||||
}
|
||||
add_extra_genesis {
|
||||
config(stakers):
|
||||
@@ -1124,6 +1130,29 @@ decl_storage! {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod migrations {
|
||||
use super::*;
|
||||
|
||||
#[derive(Decode)]
|
||||
struct OldValidatorPrefs {
|
||||
#[codec(compact)]
|
||||
pub commission: Perbill
|
||||
}
|
||||
impl OldValidatorPrefs {
|
||||
fn upgraded(self) -> ValidatorPrefs {
|
||||
ValidatorPrefs {
|
||||
commission: self.commission,
|
||||
.. Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn migrate_to_blockable<T: Config>() -> frame_support::weights::Weight {
|
||||
Validators::<T>::translate::<OldValidatorPrefs, _>(|_, p| Some(p.upgraded()));
|
||||
ErasValidatorPrefs::<T>::translate::<OldValidatorPrefs, _>(|_, _, p| Some(p.upgraded()));
|
||||
T::BlockWeights::get().max_block
|
||||
}
|
||||
}
|
||||
|
||||
decl_event!(
|
||||
pub enum Event<T> where Balance = BalanceOf<T>, <T as frame_system::Config>::AccountId {
|
||||
/// The era payout has been set; the first balance is the validator-payout; the second is
|
||||
@@ -1152,6 +1181,8 @@ decl_event!(
|
||||
/// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance`
|
||||
/// from the unlocking queue. \[stash, amount\]
|
||||
Withdrawn(AccountId, Balance),
|
||||
/// A nominator has been kicked from a validator. \[nominator, stash\]
|
||||
Kicked(AccountId, AccountId),
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1225,6 +1256,10 @@ decl_error! {
|
||||
IncorrectSlashingSpans,
|
||||
/// Internal state has become somehow corrupted and the operation cannot continue.
|
||||
BadState,
|
||||
/// Too many nomination targets supplied.
|
||||
TooManyTargets,
|
||||
/// A nomination target was supplied that was blocked or otherwise not a validator.
|
||||
BadTarget,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1270,6 +1305,15 @@ decl_module! {
|
||||
|
||||
fn deposit_event() = default;
|
||||
|
||||
fn on_runtime_upgrade() -> frame_support::weights::Weight {
|
||||
if StorageVersion::get() == Releases::V4_0_0 {
|
||||
StorageVersion::put(Releases::V5_0_0);
|
||||
migrations::migrate_to_blockable::<T>()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// sets `ElectionStatus` to `Open(now)` where `now` is the block number at which the
|
||||
/// election window has opened, if we are at the last session and less blocks than
|
||||
/// `T::ElectionLookahead` is remaining until the next new session schedule. The offchain
|
||||
@@ -1675,9 +1719,17 @@ decl_module! {
|
||||
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
|
||||
let stash = &ledger.stash;
|
||||
ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
|
||||
ensure!(targets.len() <= MAX_NOMINATIONS, Error::<T>::TooManyTargets);
|
||||
|
||||
let old = Nominators::<T>::get(stash).map_or_else(Vec::new, |x| x.targets);
|
||||
|
||||
let targets = targets.into_iter()
|
||||
.take(MAX_NOMINATIONS)
|
||||
.map(|t| T::Lookup::lookup(t))
|
||||
.map(|t| T::Lookup::lookup(t).map_err(DispatchError::from))
|
||||
.map(|n| n.and_then(|n| if old.contains(&n) || !Validators::<T>::get(&n).blocked {
|
||||
Ok(n)
|
||||
} else {
|
||||
Err(Error::<T>::BadTarget.into())
|
||||
}))
|
||||
.collect::<result::Result<Vec<T::AccountId>, _>>()?;
|
||||
|
||||
let nominations = Nominations {
|
||||
@@ -2168,6 +2220,42 @@ decl_module! {
|
||||
|
||||
Ok(adjustments)
|
||||
}
|
||||
|
||||
/// Remove the given nominations from the calling validator.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_ by the controller, not the stash.
|
||||
/// And, it can be only called when [`EraElectionStatus`] is `Closed`. The controller
|
||||
/// account should represent a validator.
|
||||
///
|
||||
/// - `who`: A list of nominator stash accounts who are nominating this validator which
|
||||
/// should no longer be nominating this validator.
|
||||
///
|
||||
/// Note: Making this call only makes sense if you first set the validator preferences to
|
||||
/// block any further nominations.
|
||||
#[weight = T::WeightInfo::kick(who.len() as u32)]
|
||||
pub fn kick(origin, who: Vec<<T::Lookup as StaticLookup>::Source>) -> DispatchResult {
|
||||
let controller = ensure_signed(origin)?;
|
||||
ensure!(Self::era_election_status().is_closed(), Error::<T>::CallNotAllowed);
|
||||
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
|
||||
let stash = &ledger.stash;
|
||||
|
||||
for nom_stash in who.into_iter()
|
||||
.map(T::Lookup::lookup)
|
||||
.collect::<Result<Vec<T::AccountId>, _>>()?
|
||||
.into_iter()
|
||||
{
|
||||
Nominators::<T>::mutate(&nom_stash, |maybe_nom| if let Some(ref mut nom) = maybe_nom {
|
||||
if let Some(pos) = nom.targets.iter().position(|v| v == stash) {
|
||||
nom.targets.swap_remove(pos);
|
||||
Self::deposit_event(RawEvent::Kicked(nom_stash.clone(), stash.clone()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user