mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 10:47:55 +00:00
Improve Staking Limits (#9193)
* only allow `chill_other` near threshold. * improve test * skip limit check for existing validators / nominators * add `ChillThreshold` * rename to `set` for consistent api * more tests * fix some line width
This commit is contained in:
@@ -1216,6 +1216,12 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
pub(crate) type StorageVersion<T: Config> = StorageValue<_, Releases, ValueQuery>;
|
||||
|
||||
/// The threshold for when users can start calling `chill_other` for other validators / nominators.
|
||||
/// The threshold is compared to the actual number of validators / nominators (`CountFor*`) in
|
||||
/// the system compared to the configured max (`Max*Count`).
|
||||
#[pallet::storage]
|
||||
pub(crate) type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;
|
||||
|
||||
#[pallet::genesis_config]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub history_depth: u32,
|
||||
@@ -1714,16 +1720,19 @@ pub mod pallet {
|
||||
pub fn validate(origin: OriginFor<T>, prefs: ValidatorPrefs) -> DispatchResult {
|
||||
let controller = ensure_signed(origin)?;
|
||||
|
||||
// If this error is reached, we need to adjust the `MinValidatorBond` and start calling `chill_other`.
|
||||
// Until then, we explicitly block new validators to protect the runtime.
|
||||
if let Some(max_validators) = MaxValidatorsCount::<T>::get() {
|
||||
ensure!(CounterForValidators::<T>::get() < max_validators, Error::<T>::TooManyValidators);
|
||||
}
|
||||
|
||||
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
|
||||
ensure!(ledger.active >= MinValidatorBond::<T>::get(), Error::<T>::InsufficientBond);
|
||||
|
||||
let stash = &ledger.stash;
|
||||
|
||||
// Only check limits if they are not already a validator.
|
||||
if !Validators::<T>::contains_key(stash) {
|
||||
// If this error is reached, we need to adjust the `MinValidatorBond` and start calling `chill_other`.
|
||||
// Until then, we explicitly block new validators to protect the runtime.
|
||||
if let Some(max_validators) = MaxValidatorsCount::<T>::get() {
|
||||
ensure!(CounterForValidators::<T>::get() < max_validators, Error::<T>::TooManyValidators);
|
||||
}
|
||||
}
|
||||
|
||||
Self::do_remove_nominator(stash);
|
||||
Self::do_add_validator(stash, prefs);
|
||||
Ok(())
|
||||
@@ -1755,16 +1764,19 @@ pub mod pallet {
|
||||
) -> DispatchResult {
|
||||
let controller = ensure_signed(origin)?;
|
||||
|
||||
// If this error is reached, we need to adjust the `MinNominatorBond` and start calling `chill_other`.
|
||||
// Until then, we explicitly block new nominators to protect the runtime.
|
||||
if let Some(max_nominators) = MaxNominatorsCount::<T>::get() {
|
||||
ensure!(CounterForNominators::<T>::get() < max_nominators, Error::<T>::TooManyNominators);
|
||||
}
|
||||
|
||||
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
|
||||
ensure!(ledger.active >= MinNominatorBond::<T>::get(), Error::<T>::InsufficientBond);
|
||||
|
||||
let stash = &ledger.stash;
|
||||
|
||||
// Only check limits if they are not already a nominator.
|
||||
if !Nominators::<T>::contains_key(stash) {
|
||||
// If this error is reached, we need to adjust the `MinNominatorBond` and start calling `chill_other`.
|
||||
// Until then, we explicitly block new nominators to protect the runtime.
|
||||
if let Some(max_nominators) = MaxNominatorsCount::<T>::get() {
|
||||
ensure!(CounterForNominators::<T>::get() < max_nominators, Error::<T>::TooManyNominators);
|
||||
}
|
||||
}
|
||||
|
||||
ensure!(!targets.is_empty(), Error::<T>::EmptyTargets);
|
||||
ensure!(targets.len() <= T::MAX_NOMINATIONS as usize, Error::<T>::TooManyTargets);
|
||||
|
||||
@@ -2266,31 +2278,42 @@ pub mod pallet {
|
||||
///
|
||||
/// NOTE: Existing nominators and validators will not be affected by this update.
|
||||
/// to kick people under the new limits, `chill_other` should be called.
|
||||
#[pallet::weight(T::WeightInfo::update_staking_limits())]
|
||||
pub fn update_staking_limits(
|
||||
#[pallet::weight(T::WeightInfo::set_staking_limits())]
|
||||
pub fn set_staking_limits(
|
||||
origin: OriginFor<T>,
|
||||
min_nominator_bond: BalanceOf<T>,
|
||||
min_validator_bond: BalanceOf<T>,
|
||||
max_nominator_count: Option<u32>,
|
||||
max_validator_count: Option<u32>,
|
||||
threshold: Option<Percent>,
|
||||
) -> DispatchResult {
|
||||
ensure_root(origin)?;
|
||||
MinNominatorBond::<T>::set(min_nominator_bond);
|
||||
MinValidatorBond::<T>::set(min_validator_bond);
|
||||
MaxNominatorsCount::<T>::set(max_nominator_count);
|
||||
MaxValidatorsCount::<T>::set(max_validator_count);
|
||||
ChillThreshold::<T>::set(threshold);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Declare a `controller` as having no desire to either validator or nominate.
|
||||
/// Declare a `controller` to stop participating as either a validator or nominator.
|
||||
///
|
||||
/// Effects will be felt at the beginning of the next era.
|
||||
///
|
||||
/// The dispatch origin for this call must be _Signed_, but can be called by anyone.
|
||||
///
|
||||
/// If the caller is the same as the controller being targeted, then no further checks
|
||||
/// are enforced. However, this call can also be made by an third party user who witnesses
|
||||
/// that this controller does not satisfy the minimum bond requirements to be in their role.
|
||||
/// If the caller is the same as the controller being targeted, then no further checks are
|
||||
/// enforced, and this function behaves just like `chill`.
|
||||
///
|
||||
/// If the caller is different than the controller being targeted, the following conditions
|
||||
/// must be met:
|
||||
/// * A `ChillThreshold` must be set and checked which defines how close to the max
|
||||
/// nominators or validators we must reach before users can start chilling one-another.
|
||||
/// * A `MaxNominatorCount` and `MaxValidatorCount` must be set which is used to determine
|
||||
/// how close we are to the threshold.
|
||||
/// * A `MinNominatorBond` and `MinValidatorBond` must be set and checked, which determines
|
||||
/// if this is a person that should be chilled because they have not met the threshold
|
||||
/// bond required.
|
||||
///
|
||||
/// This can be helpful if bond requirements are updated, and we need to remove old users
|
||||
/// who do not satisfy these requirements.
|
||||
@@ -2307,14 +2330,27 @@ pub mod pallet {
|
||||
let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;
|
||||
let stash = ledger.stash;
|
||||
|
||||
// If the caller is not the controller, we want to check that the minimum bond
|
||||
// requirements are not satisfied, and thus we have reason to chill this user.
|
||||
// In order for one user to chill another user, the following conditions must be met:
|
||||
// * A `ChillThreshold` is set which defines how close to the max nominators or
|
||||
// validators we must reach before users can start chilling one-another.
|
||||
// * A `MaxNominatorCount` and `MaxValidatorCount` which is used to determine how close
|
||||
// we are to the threshold.
|
||||
// * A `MinNominatorBond` and `MinValidatorBond` which is the final condition checked to
|
||||
// determine this is a person that should be chilled because they have not met the
|
||||
// threshold bond required.
|
||||
//
|
||||
// Otherwise, if caller is the same as the controller, this is just like `chill`.
|
||||
if caller != controller {
|
||||
let threshold = ChillThreshold::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
|
||||
let min_active_bond = if Nominators::<T>::contains_key(&stash) {
|
||||
let max_nominator_count = MaxNominatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
|
||||
let current_nominator_count = CounterForNominators::<T>::get();
|
||||
ensure!(threshold * max_nominator_count < current_nominator_count, Error::<T>::CannotChillOther);
|
||||
MinNominatorBond::<T>::get()
|
||||
} else if Validators::<T>::contains_key(&stash) {
|
||||
let max_validator_count = MaxValidatorsCount::<T>::get().ok_or(Error::<T>::CannotChillOther)?;
|
||||
let current_validator_count = CounterForValidators::<T>::get();
|
||||
ensure!(threshold * max_validator_count < current_validator_count, Error::<T>::CannotChillOther);
|
||||
MinValidatorBond::<T>::get()
|
||||
} else {
|
||||
Zero::zero()
|
||||
|
||||
Reference in New Issue
Block a user