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

Commit

Permalink
Staking: store last min-active-bond on-chain (#12889)
Browse files Browse the repository at this point in the history
* Staking: store last min-active-bond on-chain

Storing the `min-active-bond` onchain helps the UIs with minimal on-chain costs.

Closes #12746

* Avoid relying on  sorting to set the

* Addresses PR comments
  • Loading branch information
gpestana authored Dec 14, 2022
1 parent 2f6105b commit bb94ac7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
14 changes: 13 additions & 1 deletion frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,9 @@ impl<T: Config> Pallet<T> {
///
/// `maybe_max_len` can imposes a cap on the number of voters returned;
///
/// Sets `MinimumActiveStake` to the minimum active nominator stake in the returned set of
/// nominators.
///
/// This function is self-weighing as [`DispatchClass::Mandatory`].
pub fn get_npos_voters(maybe_max_len: Option<usize>) -> Vec<VoterOf<Self>> {
let max_allowed_len = {
Expand All @@ -719,6 +722,7 @@ impl<T: Config> Pallet<T> {
let mut voters_seen = 0u32;
let mut validators_taken = 0u32;
let mut nominators_taken = 0u32;
let mut min_active_stake = u64::MAX;

let mut sorted_voters = T::VoterList::iter();
while all_voters.len() < max_allowed_len &&
Expand All @@ -733,12 +737,15 @@ impl<T: Config> Pallet<T> {
};

if let Some(Nominations { targets, .. }) = <Nominators<T>>::get(&voter) {
let voter_weight = weight_of(&voter);
if !targets.is_empty() {
all_voters.push((voter.clone(), weight_of(&voter), targets));
all_voters.push((voter.clone(), voter_weight, targets));
nominators_taken.saturating_inc();
} else {
// Technically should never happen, but not much we can do about it.
}
min_active_stake =
if voter_weight < min_active_stake { voter_weight } else { min_active_stake };
} else if Validators::<T>::contains_key(&voter) {
// if this voter is a validator:
let self_vote = (
Expand Down Expand Up @@ -769,6 +776,11 @@ impl<T: Config> Pallet<T> {

Self::register_weight(T::WeightInfo::get_npos_voters(validators_taken, nominators_taken));

let min_active_stake: T::CurrencyBalance =
if all_voters.len() == 0 { 0u64.into() } else { min_active_stake.into() };

MinimumActiveStake::<T>::put(min_active_stake);

log!(
info,
"generated {} npos voters, {} from validators and {} nominators",
Expand Down
4 changes: 4 additions & 0 deletions frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,10 @@ pub mod pallet {
#[pallet::storage]
pub type MinValidatorBond<T: Config> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// The minimum active nominator stake of the last successful election.
#[pallet::storage]
pub type MinimumActiveStake<T> = StorageValue<_, BalanceOf<T>, ValueQuery>;

/// The minimum amount of commission that validators can set.
///
/// If set to `0`, no limit exists.
Expand Down
26 changes: 26 additions & 0 deletions frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4463,6 +4463,32 @@ mod election_data_provider {
);
}

#[test]
fn set_minimum_active_stake_is_correct() {
ExtBuilder::default()
.nominate(false)
.add_staker(61, 60, 2_000, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(71, 70, 10, StakerStatus::<AccountId>::Nominator(vec![21]))
.add_staker(81, 80, 50, StakerStatus::<AccountId>::Nominator(vec![21]))
.build_and_execute(|| {
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(None));
assert_eq!(MinimumActiveStake::<Test>::get(), 10);

// remove staker with lower bond by limiting the number of voters and check
// `MinimumActiveStake` again after electing voters.
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(Some(5)));
assert_eq!(MinimumActiveStake::<Test>::get(), 50);
});
}

#[test]
fn set_minimum_active_stake_zero_correct() {
ExtBuilder::default().has_stakers(false).build_and_execute(|| {
assert_ok!(<Staking as ElectionDataProvider>::electing_voters(None));
assert_eq!(MinimumActiveStake::<Test>::get(), 0);
});
}

#[test]
fn voters_include_self_vote() {
ExtBuilder::default().nominate(false).build_and_execute(|| {
Expand Down

0 comments on commit bb94ac7

Please sign in to comment.