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

Allow configuration option for minimum commission of validators #10347

Merged
merged 10 commits into from
Dec 2, 2021
11 changes: 7 additions & 4 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,21 +842,23 @@ benchmarks! {
assert_eq!(targets.len() as u32, v);
}

set_staking_limits {
set_staking_configs {
// This function always does the same thing... just write to 4 storage items.
}: _(
RawOrigin::Root,
BalanceOf::<T>::max_value(),
BalanceOf::<T>::max_value(),
Some(u32::MAX),
Some(u32::MAX),
Some(Percent::max_value())
Some(Percent::max_value()),
Perbill::max_value()
) verify {
assert_eq!(MinNominatorBond::<T>::get(), BalanceOf::<T>::max_value());
assert_eq!(MinValidatorBond::<T>::get(), BalanceOf::<T>::max_value());
assert_eq!(MaxNominatorsCount::<T>::get(), Some(u32::MAX));
assert_eq!(MaxValidatorsCount::<T>::get(), Some(u32::MAX));
assert_eq!(ChillThreshold::<T>::get(), Some(Percent::from_percent(100)));
assert_eq!(MinCommission::<T>::get(), Perbill::from_percent(100));
}

chill_other {
Expand All @@ -872,13 +874,14 @@ benchmarks! {
let stash = scenario.origin_stash1.clone();
assert!(T::SortedListProvider::contains(&stash));

Staking::<T>::set_staking_limits(
Staking::<T>::set_staking_configs(
RawOrigin::Root.into(),
BalanceOf::<T>::max_value(),
BalanceOf::<T>::max_value(),
Some(0),
Some(0),
Some(Percent::from_percent(0))
Some(Percent::from_percent(0)),
Zero::zero(),
)?;

let caller = whitelisted_caller();
Expand Down
38 changes: 33 additions & 5 deletions frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ pub mod pallet {
#[pallet::storage]
pub type MinValidatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// The minimum amount of commission that validators can set.
///
/// If set to `0`, no limit exists.
#[pallet::storage]
pub type MinCommission<T: Config> = StorageValue<_, Perbill, ValueQuery>;

/// Map from all (unlocked) "controller" accounts to the info regarding the staking.
#[pallet::storage]
#[pallet::getter(fn ledger)]
Expand Down Expand Up @@ -486,6 +492,8 @@ pub mod pallet {
Vec<(T::AccountId, T::AccountId, BalanceOf<T>, crate::StakerStatus<T::AccountId>)>,
pub min_nominator_bond: BalanceOf<T>,
pub min_validator_bond: BalanceOf<T>,
pub max_validator_count: Option<u32>,
pub max_nominator_count: Option<u32>,
}

#[cfg(feature = "std")]
Expand All @@ -502,6 +510,8 @@ pub mod pallet {
stakers: Default::default(),
min_nominator_bond: Default::default(),
min_validator_bond: Default::default(),
max_validator_count: None,
max_nominator_count: None,
}
}
}
Expand All @@ -519,6 +529,12 @@ pub mod pallet {
StorageVersion::<T>::put(Releases::V7_0_0);
MinNominatorBond::<T>::put(self.min_nominator_bond);
MinValidatorBond::<T>::put(self.min_validator_bond);
if let Some(x) = self.max_validator_count {
MaxValidatorsCount::<T>::put(x);
}
if let Some(x) = self.max_nominator_count {
MaxNominatorsCount::<T>::put(x);
}

for &(ref stash, ref controller, balance, ref status) in &self.stakers {
log!(
Expand Down Expand Up @@ -650,6 +666,8 @@ pub mod pallet {
/// There are too many validators in the system. Governance needs to adjust the staking
/// settings to keep things safe for the runtime.
TooManyValidators,
/// Commission is too low. Must be at least `MinCommission`.
CommissionTooLow,
}

#[pallet::hooks]
Expand Down Expand Up @@ -955,9 +973,13 @@ pub mod pallet {
let controller = ensure_signed(origin)?;

let ledger = Self::ledger(&controller).ok_or(Error::<T>::NotController)?;

ensure!(ledger.active >= MinValidatorBond::<T>::get(), Error::<T>::InsufficientBond);
let stash = &ledger.stash;

// ensure their commission is correct.
ensure!(prefs.commission >= MinCommission::<T>::get(), Error::<T>::CommissionTooLow);

// 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
Expand Down Expand Up @@ -1508,34 +1530,40 @@ pub mod pallet {
Ok(())
}

/// Update the various staking limits this pallet.
/// Update the various staking configurations .
///
/// * `min_nominator_bond`: The minimum active bond needed to be a nominator.
/// * `min_validator_bond`: The minimum active bond needed to be a validator.
/// * `max_nominator_count`: The max number of users who can be a nominator at once. When
/// set to `None`, no limit is enforced.
/// * `max_validator_count`: The max number of users who can be a validator at once. When
/// set to `None`, no limit is enforced.
/// * `chill_threshold`: The ratio of `max_nominator_count` or `max_validator_count` which
/// should be filled in order for the `chill_other` transaction to work.
/// * `min_commission`: The minimum amount of commission that each validators must maintain.
/// This is checked only upon calling `validate`. Existing validators are not affected.
///
/// Origin must be Root to call this function.
///
/// 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::set_staking_limits())]
pub fn set_staking_limits(
#[pallet::weight(T::WeightInfo::set_staking_configs())]
pub fn set_staking_configs(
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>,
chill_threshold: Option<Percent>,
min_commission: Perbill,
) -> 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);
ChillThreshold::<T>::set(chill_threshold);
MinCommission::<T>::set(min_commission);
Ok(())
}

Expand Down
80 changes: 70 additions & 10 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4350,7 +4350,15 @@ fn chill_other_works() {
);

// Change the minimum bond... but no limits.
assert_ok!(Staking::set_staking_limits(Origin::root(), 1_500, 2_000, None, None, None));
assert_ok!(Staking::set_staking_configs(
Origin::root(),
1_500,
2_000,
None,
None,
None,
Zero::zero()
));

// Still can't chill these users
assert_noop!(
Expand All @@ -4363,13 +4371,14 @@ fn chill_other_works() {
);

// Add limits, but no threshold
assert_ok!(Staking::set_staking_limits(
assert_ok!(Staking::set_staking_configs(
Origin::root(),
1_500,
2_000,
Some(10),
Some(10),
None
None,
Zero::zero()
));

// Still can't chill these users
Expand All @@ -4383,13 +4392,14 @@ fn chill_other_works() {
);

// Add threshold, but no limits
assert_ok!(Staking::set_staking_limits(
assert_ok!(Staking::set_staking_configs(
Origin::root(),
1_500,
2_000,
None,
None,
Some(Percent::from_percent(0))
Some(Percent::from_percent(0)),
Zero::zero()
));

// Still can't chill these users
Expand All @@ -4403,13 +4413,14 @@ fn chill_other_works() {
);

// Add threshold and limits
assert_ok!(Staking::set_staking_limits(
assert_ok!(Staking::set_staking_configs(
Origin::root(),
1_500,
2_000,
Some(10),
Some(10),
Some(Percent::from_percent(75))
Some(Percent::from_percent(75)),
Zero::zero()
));

// 16 people total because tests start with 2 active one
Expand Down Expand Up @@ -4447,13 +4458,14 @@ fn capped_stakers_works() {

// Change the maximums
let max = 10;
assert_ok!(Staking::set_staking_limits(
assert_ok!(Staking::set_staking_configs(
Origin::root(),
10,
10,
Some(max),
Some(max),
Some(Percent::from_percent(0))
Some(Percent::from_percent(0)),
Zero::zero(),
));

// can create `max - validator_count` validators
Expand Down Expand Up @@ -4516,12 +4528,60 @@ fn capped_stakers_works() {
));

// No problem when we set to `None` again
assert_ok!(Staking::set_staking_limits(Origin::root(), 10, 10, None, None, None));
assert_ok!(Staking::set_staking_configs(
Origin::root(),
10,
10,
None,
None,
None,
Zero::zero(),
));
assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1]));
assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()));
})
}

#[test]
fn min_commission_works() {
ExtBuilder::default().build_and_execute(|| {
assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
));

assert_ok!(Staking::set_staking_configs(
Origin::root(),
0,
0,
None,
None,
None,
Perbill::from_percent(10),
));

// can't make it less than 10 now
assert_noop!(
Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false }
),
Error::<Test>::CommissionTooLow
);

// can only change to higher.
assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false }
));

assert_ok!(Staking::validate(
Origin::signed(10),
ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false }
));
})
}

mod sorted_list_provider {
use super::*;
use frame_election_provider_support::SortedListProvider;
Expand Down
Loading