Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds target approvals buffering below a threshold #5168

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions polkadot/runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ parameter_types! {
pub const TargetBagThresholds: &'static [u128] = &bag_thresholds::TARGET_THRESHOLDS;

pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
pub const ScoreStrictUpdateThreshold: Option<u128> = Some(10);
}

type VoterBagsListInstance = pallet_bags_list::Instance1;
Expand All @@ -616,6 +617,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = VoterList;
type TargetList = TargetList;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = pallet_stake_tracker::weights::SubstrateWeight<Runtime>;
}

pallet_staking_reward_curve::build! {
Expand Down Expand Up @@ -667,6 +670,8 @@ impl pallet_staking::Config for Runtime {
type GenesisElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
type VoterList = VoterList;
type TargetList = TargetList;
#[cfg(any(feature = "try-runtime", test))]
type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores<Self>;
type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>;
type MaxUnlockingChunks = frame_support::traits::ConstU32<32>;
type HistoryDepth = frame_support::traits::ConstU32<84>;
Expand Down
7 changes: 7 additions & 0 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ impl pallet_staking::Config for Runtime {
type GenesisElectionProvider = onchain::OnChainExecution<OnChainSeqPhragmen>;
type VoterList = VoterList;
type TargetList = TargetList;
#[cfg(any(feature = "try-runtime", test))]
type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores<Self>;
type NominationsQuota = pallet_staking::FixedNominationsQuota<MAX_QUOTA_NOMINATIONS>;
type MaxUnlockingChunks = ConstU32<32>;
type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch;
Expand All @@ -709,6 +711,8 @@ impl pallet_staking::Config for Runtime {

parameter_types! {
pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
// disables the lazy approvals update.
pub const ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Runtime {
Expand All @@ -717,6 +721,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = VoterList;
type TargetList = TargetList;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = pallet_stake_tracker::weights::SubstrateWeight<Runtime>;
}

impl pallet_fast_unstake::Config for Runtime {
Expand Down Expand Up @@ -2646,6 +2652,7 @@ mod benches {
[pallet_session, SessionBench::<Runtime>]
[pallet_society, Society]
[pallet_staking, Staking]
[pallet_stake_tracker, StakeTracker]
[pallet_state_trie_migration, StateTrieMigration]
[pallet_sudo, Sudo]
[frame_system, SystemBench::<Runtime>]
Expand Down
5 changes: 5 additions & 0 deletions substrate/frame/delegated-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ impl pallet_staking::Config for Runtime {
type GenesisElectionProvider = Self::ElectionProvider;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = TargetBagsList;
#[cfg(any(feature = "try-runtime", test))]
type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores<Self>;
type EventListeners = (StakeTracker, Pools, DelegatedStaking);
}

Expand All @@ -129,6 +131,7 @@ impl pallet_bags_list::Config<TargetBagsListInstance> for Runtime {

parameter_types! {
pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
pub static ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Runtime {
Expand All @@ -137,6 +140,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = TargetBagsList;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = ();
}

parameter_types! {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ impl pallet_bags_list::Config<TargetBagsListInstance> for Runtime {

parameter_types! {
pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Lazy;
pub static ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Runtime {
Expand All @@ -264,6 +265,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = VoterBagsList;
type TargetList = TargetBagsList;
type VoterUpdateMode = UpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = ();
}

pub struct BalanceToU256;
Expand Down Expand Up @@ -330,6 +333,8 @@ impl pallet_staking::Config for Runtime {
type VoterList = VoterBagsList;
type NominationsQuota = pallet_staking::FixedNominationsQuota<MAX_QUOTA_NOMINATIONS>;
type TargetList = TargetBagsList;
#[cfg(any(feature = "try-runtime", test))]
type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores<Self>;
type MaxUnlockingChunks = MaxUnlockingChunks;
type EventListeners = (StakeTracker, Pools);
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
Expand Down
4 changes: 4 additions & 0 deletions substrate/frame/nomination-pools/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ impl sp_staking::StakingInterface for StakingMock {
Ok(())
}

fn validate(who: &Self::AccountId) -> sp_runtime::DispatchResult {
unimplemented!()
}

fn nominate(_: &Self::AccountId, nominations: Vec<Self::AccountId>) -> DispatchResult {
Nominations::set(&Some(nominations));
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl pallet_staking::Config for Runtime {

parameter_types! {
pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
pub static ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Runtime {
Expand All @@ -116,6 +117,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = VoterList;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = ();
}

parameter_types! {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ impl pallet_staking::Config for Runtime {

parameter_types! {
pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
pub static ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Runtime {
Expand All @@ -108,6 +109,8 @@ impl pallet_stake_tracker::Config for Runtime {
type VoterList = VoterList;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = ();
}

parameter_types! {
Expand Down
8 changes: 2 additions & 6 deletions substrate/frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{migrations::v13_stake_tracker as v13, ConfigOp, Pallet as Staking};
use testing_utils::*;

use codec::Decode;
use frame_benchmarking::v2::*;
use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider};
use frame_support::{
assert_ok,
Expand All @@ -31,18 +32,13 @@ use frame_support::{
traits::{Currency, Get, Imbalance, UnfilteredDispatchable},
weights::WeightMeter,
};
use frame_system::RawOrigin;
use sp_runtime::{
traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero},
Perbill, Percent, Saturating,
};
use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex, StakingInterface};

pub use frame_benchmarking::v1::{
account, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, BenchmarkError,
};
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;

const SEED: u32 = 0;
const MAX_SPANS: u32 = 100;
const MAX_SLASHES: u32 = 1000;
Expand Down
11 changes: 11 additions & 0 deletions substrate/frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ impl OnStakingUpdate<AccountId, Balance> for EventTracker {

parameter_types! {
pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy;
// disables the lazy approvals update.
pub static ScoreStrictUpdateThreshold: Option<u128> = None;
}

impl pallet_stake_tracker::Config for Test {
Expand All @@ -364,6 +366,8 @@ impl pallet_stake_tracker::Config for Test {
type VoterList = VoterBagsList;
type TargetList = TargetBagsList;
type VoterUpdateMode = VoterUpdateMode;
type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold;
type WeightInfo = ();
}

// Disabling threshold for `UpToLimitDisablingStrategy`
Expand All @@ -386,6 +390,8 @@ impl crate::pallet::pallet::Config for Test {
type GenesisElectionProvider = Self::ElectionProvider;
type VoterList = VoterBagsList;
type TargetList = TargetBagsList;
#[cfg(any(feature = "try-runtime", test))]
type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores<Self>;
type NominationsQuota = WeightedNominationsQuota<16>;
type MaxUnlockingChunks = MaxUnlockingChunks;
type HistoryDepth = HistoryDepth;
Expand Down Expand Up @@ -559,6 +565,11 @@ impl ExtBuilder {
MaxWinners::set(max);
self
}
pub fn stake_tracker_update_threshold(self, threshold: Option<u128>) -> Self {
ScoreStrictUpdateThreshold::set(threshold);
self
}

fn build(self) -> sp_io::TestExternalities {
sp_tracing::try_init_simple();
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
Expand Down
20 changes: 20 additions & 0 deletions substrate/frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,11 @@ impl<T: Config> StakingInterface for Pallet<T> {
Self::nominate(RawOrigin::Signed(ctrl).into(), targets)
}

fn validate(who: &Self::AccountId) -> DispatchResult {
let ctrl = Self::bonded(who).ok_or(Error::<T>::NotStash)?;
Self::validate(RawOrigin::Signed(ctrl).into(), Default::default())
}

fn desired_validator_count() -> u32 {
ValidatorCount::<T>::get()
}
Expand Down Expand Up @@ -2521,6 +2526,8 @@ impl<T: Config> Pallet<T> {
/// (active_validators + idle_validators + dangling_targets_score_with_score).
pub fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> {
use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
use pallet_stake_tracker::StakeImbalance;

let mut approvals_map: BTreeMap<T::AccountId, T::CurrencyBalance> = BTreeMap::new();

// build map of approvals stakes from the `Nominators` storage map POV.
Expand Down Expand Up @@ -2585,6 +2592,19 @@ impl<T: Config> Pallet<T> {
}
}

// sync up current unsettled score to target's approvals.
for (target, imbalance) in T::TargetUnsettledApprovals::get().into_iter() {
if let Some(approvals) = approvals_map.get_mut(&target) {
match imbalance {
StakeImbalance::Positive(score) => *approvals -= score,
StakeImbalance::Negative(score) => *approvals += score,
StakeImbalance::Zero => (),
}
} else {
return Err("unsettled approval not in the target list".into());
}
}

let mut mismatch_approvals = 0;

// compare calculated approvals per target with target list state.
Expand Down
13 changes: 13 additions & 0 deletions substrate/frame/staking/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,19 @@ pub mod pallet {
#[pallet::no_default]
type TargetList: SortedListProvider<Self::AccountId, Score = BalanceOf<Self>>;

/// Getter for unsettled approvals scores of targets in stake-tracker. Only used for
/// testing and try-state.
#[cfg(any(feature = "try-runtime", test))]
#[pallet::no_default]
type TargetUnsettledApprovals: TypedGet<
Type = Vec<(
Self::AccountId,
pallet_stake_tracker::StakeImbalance<
<Self::TargetList as SortedListProvider<Self::AccountId>>::Score,
>,
)>,
>;

/// The maximum number of `unlocking` chunks a [`StakingLedger`] can
/// have. Effectively determines how many unique eras a staker may be
/// unbonding in.
Expand Down
40 changes: 39 additions & 1 deletion substrate/frame/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7853,6 +7853,7 @@ mod stake_tracker {
use super::*;
use frame_election_provider_support::ScoreProvider;
use pallet_bags_list::Event as BagsEvent;
use pallet_stake_tracker::StakeImbalance;
use sp_staking::{StakingAccount::*, StakingInterface};

// keep tests clean;
Expand Down Expand Up @@ -8720,6 +8721,42 @@ mod stake_tracker {
);
})
}

#[test]
fn try_state_with_unsettled_score_works() {
ExtBuilder::default()
.stake_tracker_update_threshold(Some(50))
.try_state(true)
.build_and_execute(|| {
assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator));
assert_eq!(TargetBagsList::score(&11), 1500);

assert_ok!(Staking::bond(
RuntimeOrigin::signed(90),
4000,
RewardDestination::Staked
));
assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11]));

let vote_weight = Staking::weight_of(&90);

// confirm that vote weight of new nominator is lower than threshold.
assert!((vote_weight as u128) < ScoreStrictUpdateThreshold::get().unwrap());

// approvals of 42 did not updatee with nomination because new bond's vote weight
// was below the upadte threshold.
assert_eq!(TargetBagsList::score(&11), 1500);

// unsettled score map has been updated.
assert_eq!(
pallet_stake_tracker::UnsettledTargetScores::<Test>::get(),
vec![(11, StakeImbalance::Positive(vote_weight as u128))]
);

// he try-state checks takes into consideration the unsetttled score.
assert!(Staking::do_try_state(System::block_number()).is_ok());
})
}
}

mod ledger {
Expand Down Expand Up @@ -9318,7 +9355,8 @@ mod ledger_recovery {
assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK
assert_eq!(Bonded::<Test>::get(&333), Some(444)); // OK
assert!(Payee::<Test>::get(&333).is_some()); // OK
// however, ledger associated with its controller was killed.

// however, ledger associated with its controller was killed.
assert!(Ledger::<Test>::get(&444).is_none()); // NOK

// side effects on 444 - ledger, bonded, payee, lock should be completely removed.
Expand Down
2 changes: 2 additions & 0 deletions substrate/frame/staking/stake-tracker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ codec = { features = [

scale-info = { features = ["derive", "serde"], workspace = true }

sp-std = { workspace = true }
sp-runtime = { features = ["serde"], workspace = true }
sp-staking = { features = ["serde"], workspace = true }

Expand Down Expand Up @@ -56,6 +57,7 @@ std = [
"sp-runtime/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
"sp-tracing/std",
]

Expand Down
Loading
Loading