Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

Commit

Permalink
Companion for Substrate#9193
Browse files Browse the repository at this point in the history
  • Loading branch information
aurexav committed Dec 5, 2021
1 parent 8fffc47 commit f14d4d8
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 72 deletions.
100 changes: 72 additions & 28 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,12 @@ pub mod pallet {
#[pallet::storage]
pub 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 type ChillThreshold<T: Config> = StorageValue<_, Percent, OptionQuery>;

/// The chain's running time form genesis in milliseconds,
/// use for calculate darwinia era payout
#[pallet::storage]
Expand Down Expand Up @@ -1624,16 +1630,6 @@ pub mod pallet {
#[pallet::weight(T::WeightInfo::validate())]
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!(
Expand All @@ -1643,6 +1639,18 @@ pub mod pallet {

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);

Expand Down Expand Up @@ -1674,16 +1682,6 @@ pub mod pallet {
targets: Vec<<T::Lookup as StaticLookup>::Source>,
) -> 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!(
Expand All @@ -1693,6 +1691,18 @@ pub mod pallet {

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,
Expand Down Expand Up @@ -2288,33 +2298,44 @@ 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: RingBalance<T>,
min_validator_bond: RingBalance<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.
Expand All @@ -2328,14 +2349,37 @@ 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()
Expand Down
Loading

0 comments on commit f14d4d8

Please sign in to comment.